home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / ibmsyn.zip / SEMFISDD.C < prev    next >
C/C++ Source or Header  |  1993-01-13  |  202KB  |  4,275 lines

  1. /* semfisdd.c */
  2.  
  3. /* Device Driver for IBM SDLC adapter.                                       */
  4.  
  5. #ifndef IMADRIVER
  6. #error - driver code requires IMADRIVER be defined on command line
  7. #endif
  8.  
  9. #include <stddef.h>
  10. #include <ntddk.h>
  11.  
  12. #include <semfismi.h>
  13. #include <semfistr.h>
  14. #include <semfisnt.h>
  15. #include <semfisdm.h>
  16. #include <semfis73.h>
  17. #include <semfissp.h>
  18. #include <semfisis.h>
  19. #include <semfisrb.h>
  20. #include <semfisfs.h>
  21. #include <seclink.h>
  22. #include <semfisdo.h>
  23. #include <semfispr.h>
  24. #include <semfisda.h>
  25. #include <semfisel.h>
  26.  
  27.  
  28. // Temporary Usage : function prototype declaration should be pulled in
  29.  
  30. extern NTSTATUS
  31. ZwOpenKey(
  32.     OUT PHANDLE KeyHandle,
  33.     IN ACCESS_MASK DesiredAccess,
  34.     IN POBJECT_ATTRIBUTES ObjectAttributes
  35.     );
  36.  
  37.  
  38.  
  39. /* semfiddd.c - NT Device Driver for IBM SDLC adapter                        */
  40.  
  41.  
  42. /**PROC+**********************************************************************/
  43. /*                                                                           */
  44. /* Name         AdapterExistenceCheck (                                      */
  45. /*                            PCONFIGDATA pConfigData                        */
  46. /*                            );                                             */
  47. /*                                                                           */
  48. /* Purpose      Hardware-specific of initialising                            */
  49. /*                                                                           */
  50. /* Params    IN pConfigData: the config data record for adapter to be checked*/
  51. /*                                                                           */
  52. /* Return Value BOOLean:    TRUE if the adapter is present and responding    */
  53. /*                                                                           */
  54. /* Side Effect: For MPAA, sets dma channel in config data!  This will then   */
  55. /*              immediately be copied to the Device Object config data ( so  */
  56. /*              no danger of it being used by another configdata record in   */
  57. /*              error.                                                       */
  58. /*                                                                           */
  59. /* Operation:   Tries to read ports confirming the presence of the adapter   */
  60. /*              This is a trivial check of one port, suitable for start of   */
  61. /*              day checks just to tell us if the device should be created.  */
  62. /*              Real hardware initialisation is done on open.                */
  63. /*                                                                           */
  64. /* Notes        We do as little as we can get away with here because a) we   */
  65. /*              don't have a full device extension set up and b) to avoid    */
  66. /*              causing interrupts hopefully.                                */
  67. /*                                                                           */
  68. /**PROC-**********************************************************************/
  69.  
  70. BOOLean AdapterExistenceCheck (
  71.                               PCONFIGDATA pConfigData
  72.                               )
  73. {
  74.   BOOLean FoundMPA;
  75.  
  76.   if (pConfigData->AdapterType EQ AT_SDLC  ||
  77.       pConfigData->AdapterType EQ AT_MPCA1 ||
  78.       pConfigData->AdapterType EQ AT_MPCA2)
  79.   {
  80.     if (pConfigData->MPCAModePort NE 0)
  81.     {
  82.       /***********************************************************************/
  83.       /* This is an MPCA adapter, we hope.  Disable and reenable it          */
  84.       /***********************************************************************/
  85.       WR_N_DELAY (pConfigData->MPCAModePort, AC_MPCAD);
  86.       WR_N_DELAY (pConfigData->MPCAModePort, pConfigData->MPCAModeValue);
  87.  
  88.       TRACE_DATABYTE (Mpc, pConfigData->MPCAModeValue);
  89.     }
  90.  
  91.     /*************************************************************************/
  92.     /* There isn't a reliable way of determining if the MPCA/SDLC cards      */
  93.     /* are present.  So at this stage say they are and let non-existence     */
  94.     /* show up later as an Open error.                                       */
  95.     /*************************************************************************/
  96.  
  97.     return (TRUE);
  98.   }
  99.  
  100.   if (pConfigData->AdapterType EQ AT_MPAA1 ||
  101.       pConfigData->AdapterType EQ AT_MPAA2)
  102.   {
  103.     IO_ADDRESS AdapterSelector;
  104.  
  105.     for (
  106.          FoundMPA = FALSE,
  107.            AdapterSelector = (IO_ADDRESS) 8;
  108.          AdapterSelector < (IO_ADDRESS) 0x10;
  109.          AdapterSelector++
  110.         )
  111.     {
  112.       WR_N_DELAY (POS_Adapter_Select, (UCHAR) AdapterSelector);
  113.  
  114.       if (IO_IN (POS_AdapterID_HiByte)   EQ HIBYTE(POS_MPAATypeID) &&
  115.           IO_IN (POS_AdapterID_LoByte)   EQ LOBYTE(POS_MPAATypeID) &&
  116.           ((UCHAR)
  117.            (IO_IN(POS_ConfigByte2) & 0x1F)
  118.           )                              EQ pConfigData->MPAAAdapterIdentifier)
  119.       {
  120.         FoundMPA = TRUE;
  121.         pConfigData->DMAChannel = (UCHAR) (IO_IN (POS_ConfigByte3) & 7);
  122.         break;
  123.       }
  124.     }
  125.  
  126.     WR_N_DELAY (POS_Adapter_Select, 7);
  127.  
  128.     return (FoundMPA);
  129.   }
  130. }
  131.  
  132. /*****************************************************************************/
  133. /*                                                                           */
  134. /* Name         AdapterReset                                                     */
  135. /*                                                                           */
  136. /* Purpose      Reset an adapter and prime it                                */
  137. /*                                                                           */
  138. /* Params    IN pDX                                                          */
  139. /*                                                                           */
  140. /*          OUT None                                                         */
  141. /*                                                                           */
  142. /* Modified:    31/03/88 Initial coding                                      */
  143. /*                                                                           */
  144. /*****************************************************************************/
  145.  
  146. void AdapterReset (PDX pDX)
  147. {
  148.   TRACE_EVENT (<ARs);                   /* every body needs one...           */
  149.  
  150.   pDX->HardwareError = FALSE;           /* if user screwed up on hardware    */
  151.                                         /* previously, we'll let him try     */
  152.                                         /* again this time                   */
  153.  
  154.   /***************************************************************************/
  155.   /* If an MPCA has been configured then write out the mode set byte.        */
  156.   /***************************************************************************/
  157.  
  158.   if (pDX->ConfigData.MPCAModePort NE 0)
  159.   {
  160.     WR_N_DELAY (pDX->ConfigData.MPCAModePort, pDX->ConfigData.MPCAModeValue);
  161.     TRACE_DATABYTE (Mpc, pDX->ConfigData.MPCAModeValue);
  162.   }
  163.  
  164.   /***************************************************************************/
  165.   /* Now mode set the 8255.                                                  */
  166.   /***************************************************************************/
  167.  
  168.   WR_N_DELAY (pDX->ADAPTERBASE+AR_8255, A55_ModeSet);
  169.  
  170.   IO_OUT (pDX->ADAPTERBASE+AR_8255B,A55_Reset8273On);
  171.   KeStallExecutionProcessor (10L);        /* a long delay for reset on         */
  172.  
  173.   WR_N_DELAY (pDX->ADAPTERBASE+AR_8255B,A55_Reset8273Off);
  174.  
  175.   IO_OUT (pDX->ADAPTERBASE+AR_8255C, A55_InitPortC);
  176.  
  177.   TRACE_EVENT (ARs>);
  178. }
  179.  
  180. /**PROC+**********************************************************************/
  181. /*                                                                           */
  182. /* Name         AllocateDMAMemory (                                          */
  183. /*                                 int         BufferSize                    */
  184. /*                                PVOID      *pBufferPtr                     */
  185. /*                                PMDL       *pMdl                           */
  186. /*                                PHYSICAL_A *pPhysAddr                      */
  187. /*                                ULONG       *ErrorInformation              */
  188. /*                                );                                         */
  189. /*                                                                           */
  190. /* Purpose      Modularise the steps to allocate/deallocate and check DMA mem*/
  191. /*              Also, make freeing up easy (like, free everything on failure)*/
  192. /*                                                                           */
  193. /* Params   IN  BufferSize                                                   */
  194. /*          OUT BufferPtr   pointer to actual memory                         */
  195. /*          OUT pMdl        the allocated mdl                                */
  196. /*          OUT pPhysAddr   physical memory's address                        */
  197. /*          OUT ErrorInformation: suitable for IoStatus.Information          */
  198. /*                                                                           */
  199. /* Return Value BOOLean:    TRUE if everything allocated OK                  */
  200. /*                                                                           */
  201. /**PROC-**********************************************************************/
  202.  
  203. BOOLean AllocateDMAMemory (
  204.                       ULONG        BufferSize,
  205.                       PVOID      *pBufferPtr,
  206.                       PMDL      *ppMdl,
  207.                       PHYSICAL_ADDRESS * pPhysAddr,
  208.                       ULONG       *ErrorInformation
  209.                      )
  210. {
  211.   BOOLean ReturnCode = TRUE;
  212.  
  213.   TRACE_EVENT (<Dma);
  214.  
  215.   *pBufferPtr = NULL;
  216.   *ppMdl      = NULL;
  217.  
  218.   *pBufferPtr = MmAllocateContiguousMemory (BufferSize,
  219.                           RtlConvertUlongToLargeInteger (0xFFFFFFL) );
  220.   if (*pBufferPtr EQ NULL)
  221.   {
  222.     ReturnCode = FALSE;
  223.     *ErrorInformation = IO_ERR_CANT_ALLOCATE_MEMORY;
  224.   }
  225.  
  226.   if (ReturnCode)
  227.   {
  228.     *ppMdl = IoAllocateMdl(*pBufferPtr,
  229.                            BufferSize,
  230.                            FALSE,       /* this is not a secondary buffer    */
  231.                            FALSE,       /* no charge to quota                */
  232.                            (PIRP)NULL   /* not attached to IRP               */
  233.                         );
  234.     if (*ppMdl EQ NULL)
  235.     {
  236.       ReturnCode = FALSE;
  237.       *ErrorInformation = IO_ERR_CANT_ALLOCATE_MDL;
  238.     }
  239.   }
  240.   if (ReturnCode)
  241.   {
  242.     MmProbeAndLockPages (*ppMdl, KernelMode, IoModifyAccess);
  243.  
  244.     *pPhysAddr = MmGetPhysicalAddress(*pBufferPtr);
  245.     ASSERT ((pPhysAddr->LowPart | pPhysAddr->HighPart) NE 0L);
  246.  
  247.     /* check our understanding of MmAllocateContiguousMemory */
  248.  
  249.     ASSERT (BITSOFF(pPhysAddr->LowPart, 0xFF000000L));
  250.     if (DMACrosses64K(pPhysAddr->LowPart, BufferSize))
  251.     {
  252.       ReturnCode = FALSE;
  253.       *ErrorInformation = IO_ERR_DMA_BUFFER_UNUSABLE;
  254.     }
  255.   }
  256.   if (!ReturnCode)
  257.   {
  258.     if (*ppMdl NE NULL)
  259.     {
  260.       IoFreeMdl (*ppMdl);
  261.       *ppMdl     = NULL;
  262.     }
  263.     if (*pBufferPtr NE NULL)
  264.     {
  265.       MmFreeContiguousMemory (*pBufferPtr);
  266.       *pBufferPtr = NULL;
  267.     }
  268.   }
  269.  
  270.   TRACE_EVENT (Dma>);
  271.   return (ReturnCode);
  272. }
  273.  
  274. /**PROC+**********************************************************************/
  275. /*                                                                           */
  276. /* Name:        Close8273Sequence (PDX pDX)                                  */
  277. /*                                                                           */
  278. /* Purpose:     To gracefully close down the 8273                            */
  279. /*                                                                           */
  280. /* Params:   IN pDX                                                          */
  281. /*                                                                           */
  282. /* Implicit input: Must not be called at interrupt or Synchronised level!!!  */
  283. /*                                                                           */
  284. /* Return Value:none                                                         */
  285. /*                                                                           */
  286. /**PROC-**********************************************************************/
  287.  
  288. void Close8273Sequence (PDX pDX)
  289. {
  290.   TRACE_EVENT (<C73);
  291.     /*************************************************************************/
  292.     /* Clear down the transmitter and receiver and release the h/w.          */
  293.     /*************************************************************************/
  294.  
  295.     IoctlAbortTransmitter (pDX);
  296.     IoctlAbortReceiver    (pDX);
  297.  
  298.     KeSynchronizeExecution(pDX->Interrupt, SynchReset8273, (PVOID) pDX);
  299.  
  300.     /*************************************************************************/
  301.     /* Drop back down to non-interrupt level to allow pending interrupts in. */
  302.     /* The SynchReset8273 call above sets the Closing flag                   */
  303.     /*************************************************************************/
  304.  
  305.     KeSynchronizeExecution(pDX->Interrupt, SynchTerminateAdapter, (PVOID) pDX);
  306.  
  307.     pDX->AdapterIsClosing      = FALSE;
  308.   TRACE_EVENT (C73>);
  309. }
  310.  
  311. /**PROC+**********************************************************************/
  312. /*                                                                           */
  313. /* Name:        CompleteIoRequest (PIRP pIrp)                                */
  314. /*                                                                           */
  315. /* Purpose:     The Io request must be completed for each entry point.       */
  316. /*                                                                           */
  317. /* Params:   IN pIrp            The Io Request to be completed               */
  318. /*                                                                           */
  319. /* Return Value:none                                                         */
  320. /*                                                                           */
  321. /* Operation:   The Io request must be completed at despatch level           */
  322. /*                                                                           */
  323. /**PROC-**********************************************************************/
  324.  
  325. void CompleteIoRequest (PIRP pIrp)
  326. {
  327.   /***************************************************************************/
  328.   /* IoCompleteRequest used to need a RaiseIrql ... but no longer does.      */
  329.   /* Keep this as a subroutine for now - could become a macro later.         */
  330.   /***************************************************************************/
  331.  
  332. //KIRQL PreviousIrql;
  333.  
  334. //KeRaiseIrql (DISPATCH_LEVEL, &PreviousIrql);
  335.  
  336.   IoCompleteRequest (pIrp, 0);         /* 0 => no priority boost for APC    */
  337.  
  338. //KeLowerIrql (PreviousIrql);
  339.  
  340.   TRACE_EVENT (S+I:);
  341.   TRACE_DWORD (pIrp->IoStatus.Status);
  342.   TRACE_DWORD (pIrp->IoStatus.Information);
  343.  
  344. }
  345.  
  346. /**PROC+**********************************************************************/
  347. /*                                                                           */
  348. /* Name:        DeviceInit (                                                 */
  349. /*                          PDRIVER_OBJECT DriverObject                      */
  350. /*                          CHAR *         DeviceName,                       */
  351. /*                          PCONFIGDATA   pConfigData,                       */
  352. /*                         )                                                 */
  353. /*                                                                           */
  354. /* Purpose:     Initialise the next device (from GetDriverSpec)              */
  355. /*              Called for each configured device from DriverEntry.          */
  356. /*                                                                           */
  357. /* Params:   IN DriverObject:   Us!                                          */
  358. /*           IN DeviceName:     COMDL$0x (from GetDriverSpec())              */
  359. /*           IN pConfigData:    config data to use                           */
  360. /*                                                                           */
  361. /* Return Value:BOOLean:        TRUE if device successfully initialised      */
  362. /*                                                                           */
  363. /* Operation:   The general principle is: do as little as possible to here - */
  364. /*              just establish the device exists and allocate a device       */
  365. /*              object for it.  Any allocation of resources is done on open  */
  366. /*              to avoid using resources unnecessarily.  This applies to     */
  367. /*              interrupt objects,                                           */
  368. /*                                                                           */
  369. /*              0. On input, driver and flavour name read from cfg register  */
  370. /*                                                                           */
  371. /*              1. If                                                        */
  372. /*                 |--> HardwareExistenceCheck                               */
  373. /*                 fails,                                                    */
  374. /*                   return failure                                          */
  375. /*                                                                           */
  376. /*              2. Init for NT                                               */
  377. /*                 - allocate DeviceObject                                   */
  378. /*                   - DO_DIRECT_IO                                          */
  379. /*                 - IoInitializeDpcRequest                                  */
  380. /*                                                                           */
  381. /*              3. Init the device extension fields we need to know now:     */
  382. /*                 - DeviceIsOpen = FALSE                                    */
  383. /*                 - pointer to config data                                  */
  384. /*                                                                           */
  385. /* Note:        The parallel driver returns an NT status from an equivalent  */
  386. /*              routine.  Eventually, we may do the same via ErrorCode param.*/
  387. /*              But for now we don't set error code, because the NTSTATUS    */
  388. /*              returned from the parallel driver routine is ignored.        */
  389. /*                                                                           */
  390. /**PROC-**********************************************************************/
  391.  
  392. BOOLean DeviceInit (
  393.                     PDRIVER_OBJECT  pDriverObject,
  394.                     CHAR *           DeviceName,
  395.                     PCONFIGDATA     pConfigData
  396.                    )
  397. {
  398.   STRING         NameString;            /* counted string for NT             */
  399.   PDEVICE_OBJECT pDeviceObject;         /* allocated by NT for our device    */
  400.   PDX            pDX;                   /* pointer to our device extension   */
  401.   NTSTATUS       Status;
  402.   UNICODE_STRING UniNameString;         /* same thing in UniCode             */
  403.  
  404.   if (!AdapterExistenceCheck(pConfigData))
  405.   {
  406.     TRACE_EVENT (DiNa);                 /* DeviceInit: No adapter            */
  407.     DEBUG_PRINT (("IBMSYNC: Existence check failed for Adapter %s\n",
  408.                                                   pConfigData->FlavourName));
  409.     return (FALSE);                     /* no device so can't initialise devc*/
  410.   }
  411.  
  412.   RtlInitString (&NameString, DeviceName);
  413.   Status = RtlAnsiStringToUnicodeString (&UniNameString, &NameString, TRUE);
  414.   ASSERT(NT_SUCCESS(Status));           /* UniNameString now has unicode dvnm*/
  415.  
  416.   Status = IoCreateDevice(
  417.                  pDriverObject,
  418.                  sizeof( IBMSYNC_DEVICE_EXTENSION ),
  419.                  &UniNameString,
  420.                  FILE_DEVICE_DATALINK,
  421.                  0,
  422.                  TRUE,                  /* open exclusively                  */
  423.                  &pDeviceObject
  424.                  );
  425.   RtlFreeUnicodeString (&UniNameString);
  426.  
  427.   /***************************************************************************/
  428.   /* Note that we cannot log an error here since we do not hace a Device     */
  429.   /* Object.                                                                 */
  430.   /***************************************************************************/
  431.   if (!NT_SUCCESS(Status))
  432.   {
  433.     TRACE_EVENT (DiNd);                 /* DeviceInit: No device             */
  434.     DEBUG_PRINT (("IBMSYNC: Cannot create Device : %s\n", DeviceName));
  435.     return (FALSE);
  436.   }
  437.  
  438.   /***************************************************************************/
  439.   /* We have a device object OK - which is the main thing to do at device    */
  440.   /* init time.  Other initialisation stuff we leave till device opened.     */
  441.   /***************************************************************************/
  442.  
  443.   pDeviceObject->Flags       |=DO_DIRECT_IO;
  444.   pDX                        = pDeviceObject->DeviceExtension;
  445.   pDX->DeviceIsOpen          = FALSE;
  446.   pDX->AdapterIsClosing      = FALSE;
  447.   pDX->PowerFailed           = FALSE;
  448.  
  449.   /***************************************************************************/
  450.   /* In theory, we don't have to do this config data copying (we could just  */
  451.   /* use a pointer to it, but that would be a) slower; b) tedious to code    */
  452.   /***************************************************************************/
  453.  
  454.   pDX->pDeviceObject         = pDeviceObject;
  455.   pDX->ConfigData            = *pConfigData;
  456.   pDX->Name[0]               = 'A';         /* adapter                       */
  457.   pDX->Name[1]               = pConfigData->FlavourName[4];
  458.  
  459.   IoInitializeDpcRequest(pDeviceObject, DPCRoutine);
  460.  
  461.   DEBUG_PRINT (("IBMSYNC: Created Device : %s\n", DeviceName));
  462.   return (TRUE);
  463. }
  464.  
  465. /**PROC+**********************************************************************/
  466. /*                                                                           */
  467. /* Name:        DPCRoutine                                                   */
  468. /*                                                                           */
  469. /* Purpose:                                                                  */
  470. /*                                                                           */
  471. /* Params:                                                                   */
  472. /*                                                                           */
  473. /* Return Value:None                                                         */
  474. /*                                                                           */
  475. /**PROC-**********************************************************************/
  476.  
  477.  
  478. VOID  DPCRoutine(
  479.                  IN PKDPC          pDpc,
  480.                  IN PDEVICE_OBJECT pDeviceObject,
  481.                  IN PIRP           pIrp,
  482.                  IN PVOID          DeferredContext
  483.                 )
  484. {
  485.   PDX           pDX          = pDeviceObject->DeviceExtension;
  486.  
  487.   TRACE_EVENT (<DPC);
  488.  
  489.   UNREFERENCED_PARAMETER (pDpc);
  490.   UNREFERENCED_PARAMETER (pIrp);
  491.   UNREFERENCED_PARAMETER (DeferredContext);
  492.  
  493.   ASSERT (pDX->DeviceIsOpen);
  494.  
  495.   if (pDX->DeviceIsOpen &&
  496.       pDX->DPCAction & DPC_ACTION_PULSE &&
  497.       pDX->pUserEvent NE NULL)
  498.   {
  499. //    KePulseEvent (pDX->pUserEvent, 0, FALSE); /* 0 pri boost, no wait        */
  500. //    KePulseEvent missing from API?
  501.       KeSetEvent (pDX->pUserEvent, 0, FALSE);
  502.   }
  503.   pDX->DPCAction = 0;                   /* we've done all requested actions  */
  504.  
  505.   TRACE_EVENT (DPC>);
  506. }
  507.  
  508. /**PROC+**********************************************************************/
  509. /*                                                                           */
  510. /* Name:        DriverEntry(                                                 */
  511. /*                          PDRIVER_OBJECT DriverObject                      */
  512. /*                          IN PUNICODE_STRING RegistryPath                  */
  513. /*                         )                                                 */
  514. /*                                                                           */
  515. /* Purpose:     As defined by NT.  Called once only when NT loads driver     */
  516. /*                                                                           */
  517. /* Params:      PDRIVER_OBJECT: pointer to us                                */
  518. /*                                                                           */
  519. /* Return Value:NTSTATUS:       STATUS_SUCCESS / STATUS_UNSUCCESSFUL         */
  520. /*                              Unsuccessful if no devices initialised       */
  521. /*                                                                           */
  522. /**PROC-**********************************************************************/
  523.  
  524.  
  525. NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,
  526.                       IN PUNICODE_STRING RegistryPath
  527.                      )
  528. {
  529.   CHAR       DeviceName [80];
  530.   BOOLean    GotADevice = FALSE;
  531.   NTSTATUS   RetStatus  = STATUS_UNSUCCESSFUL;
  532.   CONFIGDATA *pConfigData;
  533.  
  534. //  _asm int 3;
  535.  
  536.   TRACE_INIT();
  537.   TRACE_EVENT(Entr);
  538.  
  539.   while (GetDriverSpec (DeviceName, &pConfigData))
  540.   {
  541.     if (DeviceInit (DriverObject, DeviceName, pConfigData))
  542.     {
  543.       GotADevice = TRUE;
  544.       TRACE_EVENT (DevI);
  545.     }
  546.   }
  547.  
  548.   if ((GotADevice) && (GetInterfaceType (DriverObject)))
  549.   {
  550.     DriverObject->MajorFunction[IRP_MJ_CLOSE]           = EntryPointClose;
  551.     DriverObject->MajorFunction[IRP_MJ_CREATE]          = EntryPointOpen;
  552.     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = EntryPointDevIoctl;
  553.     DriverObject->DriverUnload                          = EntryPointUnload;
  554.  
  555.     RetStatus = STATUS_SUCCESS;
  556.   }
  557.   else
  558.   {
  559.     TRACE_EVENT (DrvF);
  560.   }
  561.  
  562.   return (RetStatus);
  563. }
  564.  
  565. /*****************************************************************************/
  566. /*                                                                           */
  567. /* Name         EntryPointClose                                                     */
  568. /*                                                                           */
  569. /* Purpose      Close Request Packet Handler                                 */
  570. /*                                                                           */
  571. /*              This is the CLOSE processor.  It flushes pending requests    */
  572. /*              and ensures that the hardware and LCB fields are tidily      */
  573. /*              closed down.                                                 */
  574. /*                                                                           */
  575. /* Params    IN None                                                         */
  576. /*                                                                           */
  577. /*          OUT Link hardware closed and pending requests flushed.           */
  578. /*                                                                           */
  579. /*****************************************************************************/
  580.  
  581. NTSTATUS EntryPointClose
  582.                          (
  583.                           PDEVICE_OBJECT pDeviceObject,
  584.                           PIRP           pIrp
  585.                          )
  586. {
  587.   PDX           pDX          = pDeviceObject->DeviceExtension;
  588.  
  589.   NTSTATUS Status;
  590.  
  591.   TRACE_NEWLINE();
  592.   TRACE_EVENT ({EPC);
  593.  
  594.   pIrp->IoStatus.Information = 0;
  595.  
  596.   if (pDX->DeviceIsOpen)                /* use can close OK                  */
  597.   {
  598.     pIrp->IoStatus.Status = STATUS_SUCCESS;
  599.  
  600.     /*************************************************************************/
  601.     /* Clear down the transmitter and receiver and release the h/w.          */
  602.     /*************************************************************************/
  603.  
  604.     Close8273Sequence (pDX);            /* orderly close-down of adapter     */
  605.  
  606.     IoDisconnectInterrupt (pDX->Interrupt);
  607.  
  608.     if (pDX->ConfigData.Irql2)
  609.     {
  610.       IoDisconnectInterrupt (pDX->Interrupt2);
  611.     }
  612.  
  613.                        TRACE_EVENT (EPC1);
  614.     MmUnlockPages          (pDX->RcvInfo.pRcvMdl);
  615.                        TRACE_EVENT (EPC2);
  616.     IoFreeMdl              (pDX->RcvInfo.pRcvMdl);
  617.                        TRACE_EVENT (EPC3);
  618.     MmFreeContiguousMemory (pDX->RcvInfo.pRcvBufArray);
  619.  
  620.                        TRACE_EVENT (EPC4);
  621.     MmUnlockPages          (pDX->pSendMdl);
  622.                        TRACE_EVENT (EPC5);
  623.     IoFreeMdl              (pDX->pSendMdl);
  624.                        TRACE_EVENT (EPC6);
  625.     pDX->pSendMdl         = NULL;
  626.     MmFreeContiguousMemory (pDX->pSendBuf);
  627.                        TRACE_EVENT (EPC7);
  628.     pDX->pSendBuf         = NULL;
  629.                        TRACE_EVENT (EPC8);
  630.  
  631.   //  if (pDX->pIRMdl != NULL)                         /*IRMdl?*/
  632.   //  {                                                /*IRMdl?*/
  633.   //    MmUnmapLockedPages (pDX->pIR, pDX->pIRMdl);    /*IRMdl?*/
  634.   //    MmUnlockPages      (pDX->pIRMdl);              /*IRMdl?*/
  635.   //                     TRACE_EVENT (EPC9);           /*IRMdl?*/
  636.   //    IoFreeMdl          (pDX->pIRMdl);              /*IRMdl?*/
  637.   //                     TRACE_EVENT (EPC0);           /*IRMdl?*/
  638.   //    pDX->pIRMdl = NULL;                            /*IRMdl?*/
  639.   //  }                                                /*IRMdl?*/
  640.  
  641.     pDX->pIR    = &pDX->OurIR;
  642.  
  643.     pDX->GrabbedResources = 0;
  644.     pDX->DeviceIsOpen     = FALSE;
  645.     pDX->pUserEvent       = NULL;
  646.   }
  647.   else
  648.   {
  649.     pIrp->IoStatus.Status = STATUS_FILE_CLOSED;
  650.   }
  651.  
  652.   Status = pIrp->IoStatus.Status;
  653.   CompleteIoRequest (pIrp);
  654.  
  655.   TRACE_EVENT (EPC});
  656.   return (Status);
  657. }
  658.  
  659.  
  660. /**PROC+**********************************************************************/
  661. /*                                                                           */
  662. /* Name:        EntryPointDevIoctl (                                         */
  663. /*                          PDEVICE_OBJECT pDeviceObject                     */
  664. /*                          PIRP           pIrp                              */
  665. /*                         )                                                 */
  666. /*                                                                           */
  667. /* Purpose:     Main ioctl entry point.                                      */
  668. /*                                                                           */
  669. /* Params:   IN DeviceObject:   Our device.                                  */
  670. /*           IN PIrp            The IRP in question.                         */
  671. /*                                                                           */
  672. /* Return Value:depends on called routine                                    */
  673. /*                                                                           */
  674. /* Operation:                                                                */
  675. /*                                                                           */
  676. /**PROC-**********************************************************************/
  677.  
  678. NTSTATUS EntryPointDevIoctl (
  679.                              PDEVICE_OBJECT pDeviceObject,
  680.                              PIRP           pIrp
  681.                             )
  682. {
  683.   BOOLean       OKToContinue = TRUE;
  684.   PDX           pDX          = pDeviceObject->DeviceExtension;
  685.   PIO_STACK_LOCATION
  686.                 pIrpSp       = IoGetCurrentIrpStackLocation(pIrp);
  687.   UCHAR  *      UserBufferPtr;
  688. #ifdef IBMSYNC_TRACE
  689.   UCHAR       * OriginalTrcPtr = TrcPtr;
  690.   BOOLEAN       ResetTrcPtr    = FALSE;
  691. #endif
  692.  
  693.   ASSERT (pDX->DeviceIsOpen);           /* open before any Ioctls please     */
  694.  
  695.   TRACE_NEWLINE();
  696.   TRACE_EVENT({EPD);
  697.   TRACE_DWORD (pDeviceObject);
  698.   TRACE_DWORD (pDX);
  699.   TRACE_DWORD (pIrp);
  700.   TRACE_DWORD (pIrpSp->IRS_CODE);
  701.   TRACE_ACTION (Op,CAST(pDX->ADAPTERBASE,ULONG) & 0xFFFF);
  702.  
  703.   pDX->IoctlRetStatus = STATUS_SUCCESS;
  704.   pDX->Information    = 0L;
  705.   pDX->IoctlCurrentIrp= pIrp;
  706.  
  707.   /***************************************************************************/
  708.   /* The subroutines return the success/fail indication as their return      */
  709.   /* value, and additional information in pDX->Information                   */
  710.   /***************************************************************************/
  711.  
  712.   switch (pIrpSp->IRS_CODE)
  713.   {
  714.  
  715. //  case IoctlCodeSetInterfaceRecord                               /*IRMdl?*/
  716. //                              : IoctlSetInterfaceRecord(pDX);    /*IRMdl?*/
  717. //                                break;                           /*IRMdl?*/
  718.  
  719.     case IoctlCodeReadInterfaceRecord                              /*IRMdl?*/
  720.                                 : if (pIrpSp->IRS_OUTLEN NE sizeof(IR))
  721.                                   {
  722.                                     pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
  723.                                     pDX->Information = IO_ERR_READ_IR_BUFFER_WRONG_SIZE;
  724.                                   }
  725.                                   else
  726.                                   {
  727. #ifdef IBMSYNC_TRACE
  728.                                     ResetTrcPtr = TRUE;
  729. #endif
  730.                                     UserBufferPtr = MmMapLockedPages
  731.                                                (pIrp->MdlAddress, KernelMode);
  732.                                     memcpy (UserBufferPtr, pDX->pIR, sizeof(IR));
  733.                                   }
  734.                                   break;
  735.  
  736.     case IoctlCodeSetEvent      : if (pIrp->UserEvent NE NULL)
  737.                                   {
  738.                                     pDX->pUserEvent = pIrp->UserEvent;
  739.                                     KeSetEvent (pDX->pUserEvent, 0, FALSE);
  740.                                   }
  741.                                   else
  742.                                   {
  743.                                     pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
  744.                                     pDX->Information = IO_ERR_SET_EVENT_NO_EVENT;
  745.                                   }
  746.                                   break;
  747.  
  748.     case IoctlCodeSetLinkChar   : KeSynchronizeExecution
  749.                                        ( pDX->Interrupt,
  750.                                          (PKSYNCHRONIZE_ROUTINE)
  751.                                                             IoctlSetLinkConfig,
  752.                                          (PVOID) pDX
  753.                                        );
  754.                                   break;
  755.  
  756.     case IoctlCodeRxFrame       : KeSynchronizeExecution
  757.                                        ( pDX->Interrupt,
  758.                                          (PKSYNCHRONIZE_ROUTINE) IoctlRxFrame,
  759.                                          (PVOID) pDX
  760.                                        );
  761.                                   break;
  762.  
  763.     case IoctlCodeAbortReceiver : IoctlAbortReceiver   (pDX);
  764.                                   break;
  765.  
  766.     case IoctlCodeGetV24        : KeSynchronizeExecution
  767.                                       ( pDX->Interrupt,
  768.                                         (PKSYNCHRONIZE_ROUTINE) GetV24Input,
  769.                                         (PVOID) pDX
  770.                                       );
  771.                                   /* data-> pDX->IR; no return status */
  772. #ifdef IBMSYNC_TRACE
  773.                                   {
  774.                                     static UCHAR LastV24In = 0;
  775.                                     ResetTrcPtr = CAST(
  776.                                                   pDX->pIR->V24In EQ LastV24In,
  777.                                                        BOOLEAN);
  778.                                     LastV24In = pDX->pIR->V24In;
  779.                                   }
  780. #endif
  781.                                   break;
  782.  
  783.     case IoctlCodeTxFrame       : KeSynchronizeExecution
  784.                                       ( pDX->Interrupt,
  785.                                         (PKSYNCHRONIZE_ROUTINE) IoctlTxFrame,
  786.                                         (PVOID) pDX
  787.                                       );
  788.                                   break;
  789.  
  790.     case IoctlCodeAbortTransmit : KeSynchronizeExecution
  791.                                       ( pDX->Interrupt,
  792.                                         (PKSYNCHRONIZE_ROUTINE)
  793.                                                         IoctlAbortTransmitter,
  794.                                         (PVOID) pDX
  795.                                      );
  796.                                   break;
  797.  
  798.     case IoctlCodeSetV24        : if (!KeSynchronizeExecution
  799.                                       ( pDX->Interrupt,
  800.                                         (PKSYNCHRONIZE_ROUTINE)
  801.                                                              IoctlSetV24Output,
  802.                                         (PVOID) pDX
  803.                                       )
  804.                                      )
  805.                                   {
  806.                                     pDX->IoctlRetStatus = STATUS_DATA_ERROR;
  807.                                     pDX->Information = IO_ERR_HARDWARE_CMD_TIMEOUT_1;
  808.                                   }
  809.                                   break;
  810.  
  811.     default:
  812. //                                _asm int 3;         // break into kernel debugger
  813.                                   pDX->IoctlRetStatus =
  814.                                                     STATUS_INVALID_DEVICE_REQUEST;
  815.                                   pDX->Information = IO_ERR_INVALID_IOCTL_CODE;
  816.   }
  817.  
  818.   if (NT_SUCCESS(pDX->IoctlRetStatus))
  819.   {
  820.     // The Ioctl worked OK, but how about 8273 commands - check the
  821.     // timeout flag, which is set by 8273 WAITUNTIL macro.  Signal a fatal
  822.     // hardware error if it's set.
  823.  
  824.     if (pDX->HardwareError)
  825.     {
  826.       pDX->IoctlRetStatus = STATUS_DATA_ERROR;
  827.       pDX->Information    = IO_ERR_HARDWARE_CMD_TIMEOUT_2;
  828.     }
  829.   }
  830.   else
  831.   {
  832.     TRACE_NTFAILURE(pDX->IoctlRetStatus);
  833.     TRACE_ACTION   (Ii,pDX->Information & 0xFFFF);
  834.   }
  835.  
  836.   /***************************************************************************/
  837.   /* Note that at this point a non-zero value of pDX->Information does not   */
  838.   /* mean an error - it could be a byte count of info returned in a buffer.  */
  839.   /***************************************************************************/
  840.   if (!NT_SUCCESS(pDX->IoctlRetStatus))
  841.   {
  842.     LogDriverError( pDeviceObject,
  843.                     pDX->IoctlRetStatus,
  844.                     pDX->Information,
  845.                     pIrpSp->MajorFunction,
  846.                     pIrpSp->IRS_CODE );
  847.   }
  848.  
  849.   pIrp->IoStatus.Status      = pDX->IoctlRetStatus;
  850.   pIrp->IoStatus.Information = pDX->Information;
  851.  
  852.   TRACE_EVENT(EPD});
  853.   CompleteIoRequest (pIrp);
  854.  
  855. #ifdef IBMSYNC_TRACE
  856.   if (ResetTrcPtr)
  857.     TrcPtr = OriginalTrcPtr;
  858. #endif
  859.  
  860.   return(pDX->IoctlRetStatus);
  861. }
  862.  
  863. /**PROC+**********************************************************************/
  864. /*                                                                           */
  865. /* Name:        EntryPointISR (                                              */
  866. /*                             PKINTERRUPT pInterrupt                        */
  867. /*                             PVOID       Context = pDeviceObject           */
  868. /*                            )                                              */
  869. /*                                                                           */
  870. /* Purpose:     Handle interrupt.                                            */
  871. /*                                                                           */
  872. /* Params:   IN pInterrupt                                                   */
  873. /*           IN Context                                                      */
  874. /*                                                                           */
  875. /* Return Value:BOOLean:        TRUE if device successfully initialised      */
  876. /*                                                                           */
  877. /* Operation:                                                                */
  878. /*                                                                           */
  879. /* Notes     1. The OS/2 device driver shares interrupts; this version does  */
  880. /*              not because the interrupt object needs to be attached to a   */
  881. /*              device.  I hope we can get away it.                          */
  882. /*           2. Return value is meant to indicate some powerfail stuff ...   */
  883. /*              not bothering with it for now.                               */
  884. /*                                                                           */
  885. /**PROC-**********************************************************************/
  886.  
  887. BOOLEAN EntryPointISR (
  888.                        PKINTERRUPT pInterrupt,
  889.                        PVOID       Context
  890.                       )
  891. {
  892.   PDEVICE_OBJECT pDeviceObject= (PDEVICE_OBJECT) Context;
  893.   PDX            pDX          = pDeviceObject->DeviceExtension;
  894.   BOOLean        OriginalDPCAction  = pDX->DPCAction;
  895.   UCHAR          Status;                /* the 8273 status, not the NT Status*/
  896.   BOOLEAN        ReturnValue;
  897.  
  898.   UNREFERENCED_PARAMETER (pInterrupt);
  899.  
  900. //TRACE_NEWLINE();
  901. //TRACE_EVENT (<ISR);
  902.  
  903.   ASSERT (pDX != NULL);
  904. //TRACE_OBJECT(Ad,(*pDX));
  905.  
  906.   ASSERT (pDX->DeviceIsOpen);
  907.  
  908.   if (pDX->AdapterIsClosing ||
  909.       !pDX->DeviceIsOpen)
  910.   {
  911.     // We reset the 8273 but there was an interrupt still pending... ignore it.
  912.     // This is safe because by resetting the 8273 we should have removed the
  913.     // cause of the interrupt.
  914.     return(TRUE);
  915.   }
  916.  
  917.   ReturnValue = CAST (                                                         \
  918.                 (IO_IN (pDX->ADAPTERBASE+AR_8273S) & (AS_RXINT|AS_TXINT)) != 0,\
  919.                  BOOLEAN                                                       \
  920.                 );              /* return true if we expected the interrupt  */
  921.   do                            /* while we have an interrupt result avail.  */
  922.   {
  923.  
  924.     /*************************************************************************/
  925.     /* To be on the safe side, don't do anything further until the command   */
  926.     /* busy bit in the status register has gone off.                         */
  927.     /*************************************************************************/
  928.     WAITUNTIL (pDX, AS_CMBSY, EQ, 0);   /* wait for busy bit to go off       */
  929.  
  930.     Status = IO_IN (pDX->ADAPTERBASE+AR_8273S);
  931.     ASSERT (BITSOFF(Status, AS_CRBFF | AS_CPBFF | AS_CMBFF | AS_CMBSY));
  932.  
  933.     if (Status & AS_RXINT)      /* receiver action                           */
  934.     {
  935.       /***********************************************************************/
  936.       /* Note we don't stop DMA on receiver.  The design of the buffers has  */
  937.       /* taken into account receiving a full 8 frames+RR in DMA mode - so    */
  938.       /* that we can take account of the 8273 feature of continuing to       */
  939.       /* recieve when in DMA mode.                                           */
  940.       /***********************************************************************/
  941.  
  942.       if (Status & AS_RXIRA)
  943.       {
  944.         /*********************************************************************/
  945.         /* We have a receiver result.  Read the result bytes into the        */
  946.         /* device extension and after reading, action immediately            */
  947.         /*********************************************************************/
  948.        for (pDX->RxResultCount = 0;
  949.             pDX->RxResultCount < (sizeof (pDX->RxResultBuffer) - 1);
  950.                                        /* last byte never gets filled in !  */
  951.            )
  952.        {
  953.          pDX->RxResultBuffer[pDX->RxResultCount++] =
  954.                                          IO_IN (pDX->ADAPTERBASE + AR_8273R);
  955.  
  956.          KeStallExecutionProcessor (1L);   /* let the chip settle down again*/
  957.          WAITUNTIL(pDX, (AS_RXIRA | AS_RXINT), NE, AS_RXINT);
  958.  
  959.          TRACE_DATABYTE (RxR, pDX->RxResultBuffer[pDX->RxResultCount]);
  960.  
  961.          /*******************************************************************/
  962.          /* either the INT bit went off or IRA went on                      */
  963.          /* If INT went off, ignore the rest - even if IRA went on          */
  964.          /* (shouldn't have)                                                */
  965.          /*******************************************************************/
  966.  
  967.          if (BITSOFF(LastWaitUntilStatus, AS_RXINT))
  968.            break;
  969.        }
  970.  
  971.         /*********************************************************************/
  972.         /* We do nothing if receiver is not active.  This sitn. arises when  */
  973.         /*                                                                   */
  974.         /* - we prepare to disable the recver (start into synchronized execn)*/
  975.         /* - a result becomes available                                      */
  976.         /* - the synchronized execution carries on and disables the receiver */
  977.         /*                                                                   */
  978.         /* This only arises when we are in DMA mode - for SDLC.  (For PIO,   */
  979.         /* receiver kept active).  Make life simple by ignoring result       */
  980.         /* otherwise we get FSM's knickers in a twist.                       */
  981.         /*********************************************************************/
  982.  
  983.         if (pDX->RxFSMCurState EQ RxFSMStateReady)
  984.         {
  985.           while (pDX->RxResultCount > 0)
  986.           {
  987.             /*****************************************************************/
  988.             /* There will either be one or two result groups set.  The case  */
  989.             /* of two groups arises when one result has occurred but not     */
  990.             /* been read by the time another result comes in.                */
  991.             /*                                                               */
  992.             /* The second result is only one byte so we special case this to */
  993.             /* make it easier get the rxresults down to the start again.     */
  994.             /*****************************************************************/
  995.  
  996.             if (pDX->RxResultBuffer[0]  EQ ARxR_A1OK ||/* A1/A2 match, rcv OK */
  997.                 pDX->RxResultBuffer[0]  EQ ARxR_A2OK)
  998.             {
  999.               RxFSMEvent (pDX, RxFSMInputGoodReceive);
  1000.               pDX->RxResultBuffer[0] = pDX->RxResultBuffer[5];
  1001.               pDX->RxResultCount -= 5;
  1002.             }
  1003.             else
  1004.             {
  1005.               RxFSMEvent (pDX, RxFSMInputReceiverError);
  1006.               pDX->RxResultBuffer[0] = pDX->RxResultBuffer[1];
  1007.               pDX->RxResultCount -= 1;
  1008.             }
  1009.           }
  1010.         }
  1011.       }
  1012.       else
  1013.       {
  1014.         /*********************************************************************/
  1015.         /* IRA not set - no result available, must be for received character */
  1016.         /*                                                                   */
  1017.         /* Not that neither here nor below in tx do check for overrunning    */
  1018.         /* the buffer - we just believe 8273 is OK (and it hasn't failed in  */
  1019.         /* this area yet.  ASSERTions to guard against buffer overruns       */
  1020.         /* should be done in completion code.                                */
  1021.         /*********************************************************************/
  1022.         ASSERT (BITSOFF(pDX->GrabbedResources, GRABBEDRESOURCE_GOTDMA));
  1023.                                             /* must be PIO then              */
  1024.         *(pDX->pRxPIOData++) = IO_IN (pDX->ADAPTERBASE+AR_8273D);
  1025.  
  1026. //      TRACE_DATABYTE(RxD, *(pDX->pRxPIOData-1));
  1027.       }
  1028.     }
  1029.  
  1030.     if (Status & AS_TXINT)           /* transmitter action                           */
  1031.     {
  1032.  
  1033.       if (Status & AS_TXIRA)
  1034.       {
  1035.         /*********************************************************************/
  1036.         /* We have a transmitter result.  Read the result bytes into the     */
  1037.         /* device extension and after reading, request a DPC.                */
  1038.         /*                                                                   */
  1039.         /* The DPCAction tells the DPC why it is being called                */
  1040.         /*                                                                   */
  1041.         /* This implementation also assumes that only one transmitter result */
  1042.         /* will be outstanding at any one time, so there is only one         */
  1043.         /* TxResult byte.                                                    */
  1044.         /*********************************************************************/
  1045.  
  1046.         pDX->TxResult = IO_IN (pDX->ADAPTERBASE + AR_8273T);
  1047.         TRACE_DATABYTE (TxR, pDX->TxResult);
  1048.         if (pDX->TxResult EQ ATxR_TxCompleteOK)
  1049.         {
  1050.           TxFSMEvent (pDX, TxFSMInputEOTx);
  1051.         }
  1052.         else if (pDX->TxResult EQ ATxR_ErrTxFrameAborted)
  1053.         {
  1054.           TxFSMEvent (pDX, TxFSMInputAbortd);
  1055.         }
  1056.         else
  1057.         {
  1058.           TxFSMEvent (pDX, TxFSMInputEOTx_Err);
  1059.         }
  1060.       }
  1061.       else
  1062.       {
  1063.         /*********************************************************************/
  1064.         /* IRA not set - no result available, must be to tx next character   */
  1065.         /*********************************************************************/
  1066.         ASSERT (BITSOFF(pDX->GrabbedResources, GRABBEDRESOURCE_GOTDMA));
  1067.                                             /* must be PIO then              */
  1068. //      TRACE_DATABYTE (TxD, *pDX->pTxPIOData);
  1069.         IO_OUT(pDX->ADAPTERBASE+AR_8273D, *(pDX->pTxPIOData++));
  1070.       }
  1071.     }
  1072.     Status = IO_IN (pDX->ADAPTERBASE + AR_8273S);
  1073.   }
  1074.   while (Status & (AS_TXINT|AS_RXINT));
  1075.  
  1076.   if (!OriginalDPCAction &&             /* on entry, no dpc actions          */
  1077.       pDX->DPCAction)                   /* but on exit, we have DPC actions  */
  1078.   {
  1079.     IoRequestDpc (pDeviceObject, NULL, NULL); /* DPC will pulse event for us   */
  1080.   }
  1081.  
  1082. //XTRACE_EVENT (ISR>);
  1083.   return(ReturnValue);
  1084. }
  1085.  
  1086. /**PROC+**********************************************************************/
  1087. /*                                                                           */
  1088. /* Name:        EntryPointOpen (                                             */
  1089. /*                          PDEVICE_OBJECT pDeviceObject                     */
  1090. /*                          PIRP           pIrp                              */
  1091. /*                         )                                                 */
  1092. /*                                                                           */
  1093. /* Purpose:     Initialise the next device (from GetDriverSpec)              */
  1094. /*                                                                           */
  1095. /* Params:   IN DeviceObject:   Our device.                                  */
  1096. /*           IN PIrp            The IRP in question.                         */
  1097. /*                                                                           */
  1098. /* Return Value:BOOLean:        TRUE if device successfully initialised      */
  1099. /*                                                                           */
  1100. /* Operation:                                                                */
  1101. /*              1. Copy over pre-initialised data sequences                  */
  1102. /*                                                                           */
  1103. /*              2. Init for NT                                               */
  1104. /*                 - allocate transmit and receive buffers DMA-able          */
  1105. /*                 - DeviceObject                                            */
  1106. /*                   - DO_DIRECT_IO                                          */
  1107. /*                 - IoInitializeDpcRequest                                  */
  1108. /*                 - ConnectInterrupt                                        */
  1109. /*                                                                           */
  1110. /*              3. Init our own data                                         */
  1111. /*                 - DeviceIsOpen = FALSE                                    */
  1112. /*                                                                           */
  1113. /**PROC-**********************************************************************/
  1114.  
  1115. NTSTATUS EntryPointOpen (
  1116.                          PDEVICE_OBJECT pDeviceObject,
  1117.                          PIRP           pIrp
  1118.                         )
  1119. {
  1120. //ULONG         AddressSpace;
  1121.   KAFFINITY     Affinity;
  1122.   int           Information  = 0;
  1123.   KIRQL         InterruptLevel;
  1124.   CCHAR         InterruptVector;
  1125.   BOOLean       OKToContinue = TRUE;
  1126.   PDX           pDX          = pDeviceObject->DeviceExtension;
  1127.   NTSTATUS      Status       = STATUS_UNSUCCESSFUL;
  1128.   int           WindDownLevel= 0;
  1129.  
  1130.   ASSERT (!pDX->DeviceIsOpen);          /* device defined as exclusive usage!*/
  1131.  
  1132.   TRACE_NEWLINE();
  1133.   TRACE_EVENT({EPO);
  1134.   TRACE_ACTION (Op,CAST(pDX->ADAPTERBASE, ULONG) & 0xFFFF);
  1135.  
  1136.   pIrp->IoStatus.Information = 0L;
  1137.  
  1138.   pDX->GrabbedResources = 0;            /* clear the list of resources       */
  1139.  
  1140.  
  1141.  
  1142.   if (InterfaceType == MicroChannel)
  1143.   {
  1144.     if (!pDX->ConfigData.MPAAAdapterIdentifier)
  1145.     {
  1146.       OKToContinue = FALSE;
  1147.       Status       = STATUS_INSUFFICIENT_RESOURCES;
  1148.       Information  = IO_ERR_NEEDS_ISA_BUS;
  1149.       TRACE_EVENT (OcWb);
  1150.     }
  1151.   }
  1152.   else
  1153.   {
  1154.     if (pDX->ConfigData.MPAAAdapterIdentifier)
  1155.     {
  1156.       OKToContinue = FALSE;
  1157.       Status       = STATUS_INSUFFICIENT_RESOURCES;
  1158.       Information  = IO_ERR_NEEDS_MCA_BUS;
  1159.       TRACE_EVENT (OcWb);
  1160.     }
  1161.   }
  1162.  
  1163.  
  1164.   //
  1165.   // Map the memory for the control registers for the parallel device
  1166.   // into virtual memory.  This code needs to be activated when moving to
  1167.   // a platform with memory-mapped I/O.
  1168.   //
  1169.  
  1170. //  AddressSpace = pDX->ConfigData.AddressSpace;
  1171. //  CardAddress  = HalTranslateBusAddress(
  1172. //                    InterfaceType,
  1173. //                    pDX->ConfigData->BusNumber,
  1174. //                    pDX->ConfigData->AdapterBaseAddress,
  1175. //                    &AddressSpace
  1176. //                    );
  1177. //
  1178. //  if (!AddressSpace)
  1179. //  {
  1180. //      ParDeviceObject->UnMapRegisters = TRUE;
  1181. //      ParDeviceObject->DeviceRegisters = MmMapIoSpace(
  1182. //                                       CardAddress,
  1183. //                                       PARALLEL_REGISTER_LENGTH,
  1184. //                                       FALSE
  1185. //                                       );
  1186. //
  1187. //  } else {
  1188. //
  1189. //      ParDeviceObject->UnMapRegisters = FALSE;
  1190. //      ParDeviceObject->DeviceRegisters = (PVOID)CardAddress.LowPart;
  1191. //
  1192. //  }
  1193. //
  1194. //  if (!ParDeviceObject->DeviceRegisters) {
  1195. //
  1196. //      DbgPrint("Couldn't map the device registers.\n");
  1197. //      IoDeleteDevice(DeviceObject);
  1198. //      return STATUS_NONE_MAPPED;
  1199. //
  1200. //  }
  1201.  
  1202.  
  1203.   /***************************************************************************/
  1204.   /* 1. NT-related device initialisation                                     */
  1205.   /***************************************************************************/
  1206.  
  1207.   if (OKToContinue)
  1208.   {
  1209.     InterruptVector = HalGetInterruptVector(
  1210.                           InterfaceType,
  1211.                           pDX->ConfigData.BusNumber,
  1212.                           pDX->ConfigData.Irql,
  1213.                           pDX->ConfigData.Vector,
  1214.                           &InterruptLevel,
  1215.                           &Affinity
  1216.                           );
  1217.  
  1218.     Status = IoConnectInterrupt (
  1219.                 &pDX->Interrupt,
  1220.                  EntryPointISR,
  1221.                  pDeviceObject,
  1222.                  NULL,
  1223.                  InterruptVector,
  1224.                  InterruptLevel,                /* interrupt IRQ level       */
  1225.                  InterruptLevel,                /* synchronize IRQ level     */
  1226.                  pDX->ConfigData.InterruptMode,
  1227.                  pDX->ConfigData.Shareable,
  1228.                  Affinity,                      /* processor number          */
  1229.                  FALSE                          /* no save floating pt contxt*/
  1230.                  );
  1231.  
  1232.     if (!NT_SUCCESS(Status))
  1233.     {
  1234.       OKToContinue = FALSE;
  1235.       Status       = STATUS_INSUFFICIENT_RESOURCES;
  1236.       Information  = IO_ERR_CANT_CONNECT_INTERRUPT_1;
  1237.       TRACE_EVENT (OcCi);
  1238.     }
  1239.   }
  1240.  
  1241.   if (OKToContinue)
  1242.   {
  1243.     WindDownLevel = 15;
  1244.  
  1245.     if (pDX->ConfigData.Irql2)
  1246.     {
  1247.       /***********************************************************************/
  1248.       /* A second interrupt is required                                      */
  1249.       /***********************************************************************/
  1250.       ASSERT (pDX->ConfigData.FlavourName[0] EQ 'S');
  1251.                                         /* only the SDLC card is so dumb     */
  1252.  
  1253.  
  1254.       if (OKToContinue)
  1255.       {
  1256.         InterruptVector = HalGetInterruptVector(
  1257.                               InterfaceType,
  1258.                               pDX->ConfigData.BusNumber,
  1259.                               pDX->ConfigData.Irql2,
  1260.                               pDX->ConfigData.Vector2,
  1261.                               &InterruptLevel,
  1262.                               &Affinity
  1263.                               );
  1264.  
  1265.         Status = IoConnectInterrupt (
  1266.                     &pDX->Interrupt2,
  1267.                      EntryPointRogueInterrupt,
  1268.                      pDeviceObject,
  1269.                      NULL,
  1270.                      InterruptVector,
  1271.                      InterruptLevel,                /* interrupt IRQ level       */
  1272.                      InterruptLevel,                /* synchronize IRQ level     */
  1273.                      pDX->ConfigData.InterruptMode2,
  1274.                      pDX->ConfigData.Shareable2,
  1275.                      1,                         /* processor number          */
  1276.                      FALSE                      /* no save floating pt contxt*/
  1277.                      );
  1278.  
  1279.         if (!NT_SUCCESS(Status))
  1280.         {
  1281.           OKToContinue = FALSE;
  1282.           Status       = STATUS_INSUFFICIENT_RESOURCES;
  1283.           Information  = IO_ERR_CANT_CONNECT_INTERRUPT_2;
  1284.           TRACE_EVENT (OcCi);
  1285.         }
  1286.       }
  1287.     }
  1288.   }
  1289.  
  1290.   /***************************************************************************/
  1291.   /* 2. Buffer allocation and init                                           */
  1292.   /***************************************************************************/
  1293.  
  1294.   if (OKToContinue)
  1295.   {
  1296.     WindDownLevel = 20;
  1297.     OKToContinue  = AllocateDMAMemory (sizeof(RCVBUFARRAY),
  1298.                                        (PVOID *)&pDX->RcvInfo.pRcvBufArray,
  1299.                                        &pDX->RcvInfo.pRcvMdl,
  1300.                                        &pDX->RcvInfo.RcvBufPhysAddr,
  1301.                                        &Information
  1302.                                       );
  1303.     if (!OKToContinue)
  1304.     {
  1305.       Status = STATUS_INSUFFICIENT_RESOURCES;
  1306.       // Information set in above call to AllocateDmaMemory
  1307.     }
  1308.   }
  1309.   if (OKToContinue)
  1310.   {
  1311.     WindDownLevel = 30;
  1312.  
  1313.     RCVINFO_INIT(pDX);
  1314.  
  1315.     pDX->RxFSMCurState = RxFSMStateIdle;
  1316.     OKToContinue       = AllocateDMAMemory (SENDBUF_SIZE,
  1317.                                             (PVOID *)&pDX->pSendBuf,
  1318.                                             &pDX->pSendMdl,
  1319.                                             &pDX->SendBufPhysAddr,
  1320.                                             &Information
  1321.                                            );
  1322.     if (!OKToContinue)
  1323.     {
  1324.       Status = STATUS_INSUFFICIENT_RESOURCES;
  1325.       // Information set in above call to AllocateDmaMemory
  1326.     }
  1327.   }
  1328.   if (OKToContinue)
  1329.   {
  1330.     WindDownLevel      = 40;
  1331.     pDX->TxFSMCurState = TxFSMStateIdle;
  1332.     pDX->TxConsecutiveUnderrunCount = 0;
  1333.  
  1334.     COPY8273CMD (pDX, CmdStringReadPortA        );
  1335.     COPY8273CMD (pDX, CmdStringResetOpMode      );
  1336.     COPY8273CMD (pDX, CmdStringResetSerialIOMode);
  1337.     COPY8273CMD (pDX, CmdStringSetOpMode        );
  1338.     COPY8273CMD (pDX, CmdStringSetSerialIOMode  );
  1339.     COPY8273CMD (pDX, CmdStringDataTransferMode );
  1340.     COPY8273CMD (pDX, CmdStringResetPortB       );
  1341.     COPY8273CMD (pDX, CmdStringSetPortB         );
  1342.     COPY8273CMD (pDX, CmdStringReceive          );
  1343.     COPY8273CMD (pDX, CmdStringTransmit         );
  1344.     COPY8273CMD (pDX, CmdStringAbortTransmit    );
  1345.     COPY8273CMD (pDX, CmdStringDisableReceiver  );
  1346.  
  1347.     pDX->pIR          = &pDX->OurIR;    /* use dummy IR for now until real   */
  1348.  
  1349.     pDX->pIR->V24In   = 0;
  1350.     pDX->pIR->V24Out  = 0;
  1351.     pDX->pIR->RxFrameCount= 0;
  1352.     pDX->pIR->TxMaxFrSizeNow = INIT_MAXFRSIZENOW;
  1353.  
  1354. //  pDX->pIRMdl = NULL;                 /*IRMdl?*/
  1355.  
  1356.     pDX->pUserEvent = NULL;             /* null until Ioctl: SetEvent        */
  1357.   }
  1358.  
  1359.   /***************************************************************************/
  1360.   /*    SDLC device initialisation                                           */
  1361.   /***************************************************************************/
  1362.   if (OKToContinue)
  1363.   {
  1364.     if (!KeSynchronizeExecution(pDX->Interrupt,
  1365.                                 SynchEntryPointOpen,
  1366.                                 (PVOID)pDX))
  1367.     {
  1368.       Status       = STATUS_DATA_ERROR;
  1369.       Information  = pDX->Information;
  1370.       OKToContinue = FALSE;
  1371.     }
  1372.   }
  1373.  
  1374.   if (OKToContinue)
  1375.   {
  1376.     if (pDX->HardwareError)
  1377.     {
  1378.       Status       = STATUS_DATA_ERROR;
  1379.       Information  = IO_ERR_HARDWARE_CMD_TIMEOUT_3;
  1380.       OKToContinue = FALSE;
  1381.     }
  1382.   }
  1383.  
  1384.   if (!OKToContinue)
  1385.   {
  1386.     TRACE_ACTION (Wl, WindDownLevel & 0xFFFF);
  1387.  
  1388.     if (WindDownLevel >= 15)
  1389.       IoDisconnectInterrupt( pDX->Interrupt);
  1390.  
  1391.     if (pDX->ConfigData.Irql2)
  1392.     {
  1393.       if (WindDownLevel >= 20)
  1394.         IoDisconnectInterrupt( pDX->Interrupt2);
  1395.     }
  1396.  
  1397.     if (WindDownLevel >= 30)
  1398.     {
  1399.       MmUnlockPages          (pDX->RcvInfo.pRcvMdl);
  1400.       IoFreeMdl              (pDX->RcvInfo.pRcvMdl);
  1401.       MmFreeContiguousMemory (pDX->RcvInfo.pRcvBufArray);
  1402.     }
  1403.     if (WindDownLevel >= 40)
  1404.     {
  1405.       MmUnlockPages          (pDX->pSendMdl);
  1406.       IoFreeMdl              (pDX->pSendMdl);
  1407.       pDX->pSendMdl         = NULL;
  1408.       MmFreeContiguousMemory (pDX->pSendBuf);
  1409.       pDX->pSendBuf         = NULL;
  1410.     }
  1411.  
  1412.     LogDriverError( pDeviceObject,
  1413.                     Status,
  1414.                     Information,
  1415.                     IoGetCurrentIrpStackLocation(pIrp)->MajorFunction,
  1416.                     0L );
  1417.   }
  1418.  
  1419.   pIrp->IoStatus.Status = Status;
  1420.   pIrp->IoStatus.Information = Information;
  1421.   if (Status EQ STATUS_SUCCESS)
  1422.   {
  1423.     pDX->DeviceIsOpen = TRUE;
  1424.   }
  1425.  
  1426.   TRACE_EVENT(EPO});
  1427.   TRACE_NTFAILURE (Status);
  1428.  
  1429.   CompleteIoRequest (pIrp);
  1430.   return (Status);
  1431. }
  1432.  
  1433. /*****************************************************************************/
  1434. /*                                                                           */
  1435. /* Name         EntryPointRogueInterrupt                                     */
  1436. /*                                                                           */
  1437. /* Purpose      Mode Status ISR.                                             */
  1438. /*                                                                           */
  1439. /*              Should never be called!!!  This ISR is used to handle int4   */
  1440. /*              on SDLC cards (modem status and timers).  Since the int is   */
  1441. /*              explicitly masked off in adapter set-up, it is a severe err  */
  1442. /*              if we actually get one!                                      */
  1443. /*                                                                           */
  1444. /*                                                                           */
  1445. /* Params    IN None                                                         */
  1446. /*                                                                           */
  1447. /*          OUT DLC appl hardware status updated.                            */
  1448. /*                                                                           */
  1449. /*****************************************************************************/
  1450.  
  1451. BOOLEAN EntryPointRogueInterrupt (
  1452.                                   PKINTERRUPT pInterrupt,
  1453.                                   PVOID       Context
  1454.                                  )
  1455. {
  1456.   PDEVICE_OBJECT pDeviceObject= (PDEVICE_OBJECT) Context;
  1457.   PDX            pDX          = pDeviceObject->DeviceExtension;
  1458.  
  1459.   UNREFERENCED_PARAMETER (pInterrupt);
  1460.  
  1461.   TRACE_EVENT ({EP?);
  1462.  
  1463.   /***************************************************************************/
  1464.   /* Update hardware error status and trigger an event for Link process via  */
  1465.   /* DPC                                                                     */
  1466.   /***************************************************************************/
  1467.  
  1468.   pDX->pIR->StatusArray[SA_HardwareError]++;
  1469.   pDX->pIR->StatusCount++;
  1470.  
  1471.   pDX->DPCAction |= DPC_ACTION_PULSE;
  1472.   IoRequestDpc (pDeviceObject, NULL, NULL); /* DPC will pulse event for us   */
  1473.  
  1474.   /***************************************************************************/
  1475.   /* Reset the modem status logic and turn the 8273 off - it is being too    */
  1476.   /* disruptive to keep active!                                              */
  1477.   /***************************************************************************/
  1478.  
  1479.   WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, A55_ResetModemStatusCh+
  1480.                                            A55_Reset8273Off);
  1481.   WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, A55_Reset8273Off);
  1482.  
  1483.   TRACE_EVENT (EP?});
  1484.   return(FALSE);                        /* interrupt wasn't expected         */
  1485. }
  1486.  
  1487. /**PROC+**********************************************************************/
  1488. /*                                                                           */
  1489. /* Name:        EntryPointUnload (                                           */
  1490. /*                          PDRIVER_OBJECT pDriverObject                     */
  1491. /*                         )                                                 */
  1492. /*                                                                           */
  1493. /* Purpose:     Unload the device - don't need to do anything?               */
  1494. /*                                                                           */
  1495. /* Params:   IN DriverObject:   Our device.                                  */
  1496. /*                                                                           */
  1497. /* Return Value:None                                                         */
  1498. /*                                                                           */
  1499. /* Operation:                                                                */
  1500. /*                                                                           */
  1501. /**PROC-**********************************************************************/
  1502.  
  1503. VOID
  1504. EntryPointUnload (
  1505.                   IN PDRIVER_OBJECT pDriverObject
  1506.                  )
  1507. {
  1508.   IoDeleteDevice( pDriverObject->DeviceObject );
  1509.   return;
  1510. }
  1511.  
  1512. /**PROC+**********************************************************************/
  1513. /*                                                                           */
  1514. /* Name         GetInterfaceType (                                           */
  1515. /*                                PDRIVER_OBJECT pDriverObject               */
  1516. /*                               )                                           */
  1517. /*                                                                           */
  1518. /* Purpose      Hide the vagaries of roasting squirrels                      */
  1519. /*                                                                           */
  1520. /* Return Value BOOLean : TRUE if InterfaceType (global) set up OK           */
  1521. /*                                                                           */
  1522. /**PROC-**********************************************************************/
  1523.  
  1524. BOOLean GetInterfaceType (
  1525.                           IN PDRIVER_OBJECT  pDriverObject
  1526.                          )
  1527. {
  1528.  
  1529.   PUNICODE_STRING           RegistryPath = pDriverObject->HardwareDatabase;
  1530.   PRTL_QUERY_REGISTRY_TABLE Parameters = NULL;
  1531.   UNICODE_STRING            ParametersPath;
  1532.   OBJECT_ATTRIBUTES         ParametersAttributes;
  1533.   HANDLE                    ParametersKey;
  1534.   UNICODE_STRING            Identifier;
  1535.   UNICODE_STRING            MCAString;
  1536.   NTSTATUS                  Status = STATUS_SUCCESS;
  1537.   ULONG                     Information;
  1538.  
  1539.  
  1540.   TRACE_EVENT([GIT);
  1541.  
  1542.   Identifier.Buffer = NULL;
  1543.  
  1544.   /***************************************************************************/
  1545.   /* Set up the Registry path to check if \EisaAdapter\0 key exists.         */
  1546.   /***************************************************************************/
  1547.  
  1548.   RtlInitUnicodeString (&ParametersPath, NULL);
  1549.  
  1550.   ParametersPath.MaximumLength = RegistryPath->Length +
  1551.                                  sizeof(L"\\MultifunctionAdapter\\0") +
  1552.                                  4;
  1553.  
  1554.   ParametersPath.Buffer = ExAllocatePool(
  1555.                               PagedPool,
  1556.                               ParametersPath.MaximumLength
  1557.                               );
  1558.  
  1559.   if (!ParametersPath.Buffer)
  1560.   {
  1561.     TRACE_EVENT (GIT1);
  1562.     Information = IO_ERR_GET_IF_TYPE_1;
  1563.     Status      = STATUS_UNSUCCESSFUL;
  1564.   }
  1565.   else
  1566.   {
  1567.  
  1568.     RtlZeroMemory(
  1569.         ParametersPath.Buffer,
  1570.         ParametersPath.MaximumLength
  1571.         );
  1572.     RtlAppendUnicodeStringToString(
  1573.         &ParametersPath,
  1574.         RegistryPath
  1575.         );
  1576.     RtlAppendUnicodeToString(
  1577.         &ParametersPath,
  1578.         L"\\EisaAdapter\\0"
  1579.         );
  1580.  
  1581.     /*************************************************************************/
  1582.     /* Attempt to open the key - if we can this is Eisa bus.                 */
  1583.     /*************************************************************************/
  1584.  
  1585.     InitializeObjectAttributes(
  1586.         &ParametersAttributes,
  1587.         &ParametersPath,
  1588.         OBJ_CASE_INSENSITIVE,
  1589.         NULL,
  1590.         NULL
  1591.         );
  1592.  
  1593.     if (NT_SUCCESS(ZwOpenKey(
  1594.                        &ParametersKey,
  1595.                        MAXIMUM_ALLOWED,
  1596.                        &ParametersAttributes
  1597.                        )))
  1598.     {
  1599.       InterfaceType = Eisa;
  1600.       TRACE_EVENT (Eisa);
  1601.       DEBUG_PRINT (("IBMSYNC: Bus type is Eisa\n"));
  1602.       TRACE_EVENT(GIT]);
  1603.  
  1604.       ExFreePool(ParametersPath.Buffer);
  1605.       return(TRUE);
  1606.     }
  1607.   }
  1608.  
  1609.  
  1610.  
  1611.   if (NT_SUCCESS(Status))
  1612.   {
  1613.     /*************************************************************************/
  1614.     /* Reset the Registry path to check for Identifier string in key         */
  1615.     /* \MultifunctionAdapter\0.                                              */
  1616.     /*************************************************************************/
  1617.  
  1618.     RtlZeroMemory(
  1619.         ParametersPath.Buffer,
  1620.         ParametersPath.MaximumLength
  1621.         );
  1622.  
  1623.     ParametersPath.Length = 0;
  1624.  
  1625.     RtlAppendUnicodeStringToString(
  1626.         &ParametersPath,
  1627.         RegistryPath
  1628.         );
  1629.     RtlAppendUnicodeToString(
  1630.         &ParametersPath,
  1631.         L"\\MultifunctionAdapter\\0"
  1632.         );
  1633.  
  1634.     /*************************************************************************/
  1635.     /* Allocate the Rtl query table.                                         */
  1636.     /*************************************************************************/
  1637.  
  1638.     Parameters = ExAllocatePool(
  1639.                      PagedPool,
  1640.                      sizeof(RTL_QUERY_REGISTRY_TABLE) * 2
  1641.                      );
  1642.  
  1643.     if (!Parameters)
  1644.     {
  1645.       TRACE_EVENT (GIT2);
  1646.       Information = IO_ERR_GET_IF_TYPE_2;
  1647.       Status      = STATUS_UNSUCCESSFUL;
  1648.     }
  1649.     else
  1650.     {
  1651.  
  1652.       /***********************************************************************/
  1653.       /* Allocate memory to except Identifier type.                          */
  1654.       /***********************************************************************/
  1655.       RtlInitUnicodeString (&Identifier, NULL);
  1656.  
  1657.       Identifier.MaximumLength = 20;    /* Room for "EISA", "MCA" or "ISA"   */
  1658.  
  1659.       Identifier.Buffer = ExAllocatePool(
  1660.                                   PagedPool,
  1661.                                   Identifier.MaximumLength
  1662.                                   );
  1663.  
  1664.       if (!Identifier.Buffer)
  1665.       {
  1666.         TRACE_EVENT (GIT3);
  1667.         Information = IO_ERR_GET_IF_TYPE_3;
  1668.         Status      = STATUS_UNSUCCESSFUL;
  1669.       }
  1670.       else
  1671.       {
  1672.         /*********************************************************************/
  1673.         /* OK now finally pick up the Bus Type (Identifier) string from the  */
  1674.         /* Registry.                                                         */
  1675.         /*********************************************************************/
  1676.  
  1677.         RtlZeroMemory(
  1678.               Parameters,
  1679.               sizeof(RTL_QUERY_REGISTRY_TABLE) * 2
  1680.               );
  1681.  
  1682.         Parameters[0].Flags         = RTL_QUERY_REGISTRY_DIRECT;
  1683.         Parameters[0].Name          = L"Identifier";
  1684.         Parameters[0].EntryContext  = &Identifier;
  1685.         Parameters[0].DefaultType   = REG_SZ;
  1686.         Parameters[0].DefaultData   = L"None";
  1687.         Parameters[0].DefaultLength = 8;
  1688.  
  1689.  
  1690.         if (!NT_SUCCESS(RtlQueryRegistryValues(
  1691.                            RTL_REGISTRY_ABSOLUTE,
  1692.                            ParametersPath.Buffer,
  1693.                            Parameters,
  1694.                            NULL,
  1695.                            NULL
  1696.                            )))
  1697.         {
  1698.           TRACE_EVENT (GIT4);
  1699.           Information = IO_ERR_GET_IF_TYPE_4;
  1700.           Status      = STATUS_UNSUCCESSFUL;
  1701.         }
  1702.         else
  1703.         {
  1704.           RtlInitUnicodeString (&MCAString, L"MCA");
  1705.  
  1706.           if (!RtlCompareUnicodeString(&MCAString, &Identifier, TRUE))
  1707.           {
  1708.             InterfaceType = MicroChannel;
  1709.             TRACE_EVENT (MCA );
  1710.             DEBUG_PRINT (("IBMSYNC: Bus type is MicroChannel\n"));
  1711.           }
  1712.           else
  1713.           {
  1714.             InterfaceType = Isa;
  1715.             TRACE_EVENT (ISA );
  1716.             DEBUG_PRINT (("IBMSYNC: Bus type is Isa\n"));
  1717.           }
  1718.         }
  1719.       }
  1720.     }
  1721.   }
  1722.  
  1723.   /***************************************************************************/
  1724.   /* Free any allocated memory before returning.                             */
  1725.   /***************************************************************************/
  1726.  
  1727.   if (ParametersPath.Buffer)
  1728.       ExFreePool(ParametersPath.Buffer);
  1729.  
  1730.   if (Identifier.Buffer)
  1731.       ExFreePool(Identifier.Buffer);
  1732.  
  1733.   if (Parameters)
  1734.       ExFreePool(Parameters);
  1735.  
  1736.   /***************************************************************************/
  1737.   /* OK, so which Device Object do we use here?  The driver can have         */
  1738.   /* multiple Device Objects set up; also the reading of the bus type from   */
  1739.   /* the Registry is done just once (i.e not on a per-Device basis).         */
  1740.   /*                                                                         */
  1741.   /* We use the last one hanging from the list - to get to this stage we     */
  1742.   /* must have at least one.                                                 */
  1743.   /***************************************************************************/
  1744.   if (!NT_SUCCESS(Status))
  1745.   {
  1746.     LogDriverError( pDriverObject->DeviceObject,
  1747.                     Status,
  1748.                     Information,
  1749.                     0L,
  1750.                     0L );
  1751.   }
  1752.  
  1753.  
  1754.   TRACE_EVENT(GIT]);
  1755.  
  1756.   return(Status == STATUS_SUCCESS);
  1757.  
  1758. }
  1759.  
  1760. /**PROC+**********************************************************************/
  1761. /*                                                                           */
  1762. /* Name         GetDriverSpec (                                              */
  1763. /*                             CHAR *DriverName,                             */
  1764. /*                            PCONFIGDATA *pConfigData                       */
  1765. /*                            );                                             */
  1766. /*                                                                           */
  1767. /* Purpose      Hide the vagaries of initialising                            */
  1768. /*                                                                           */
  1769. /* Params   OUT DriverName: e.g. COM$DL01, null-terminated, 8+1 chars        */
  1770. /*          OUT FlavourName: e.g. SDLC or MPAA1, null-terminated, 5+1 chars  */
  1771. /*          OUT pConfigData: the config data record to be set up             */
  1772. /*                           (a pointer is passed, not the structure itself) */
  1773. /*                                                                           */
  1774. /* Return Value BOOLean:    TRUE if there was another driver spec to get     */
  1775. /*                                                                           */
  1776. /* Operation    At a guess, this will                                        */
  1777. /*              - enumerate all SDLC device drivers in CFG Reg.              */
  1778. /*                (RegEnumKeyEx(Key:Master\Software\CS\Drivers)              */
  1779. /*                  or CS\SDLCDrivers?                                       */
  1780. /*              - if necessary, check the driver is an SDLC one              */
  1781. /*              - read config info to extract device name and type           */
  1782. /*              - get other config data into ConfigData                      */
  1783. /*                                                                           */
  1784. /* Notes        Uses static variables to indicate position in config; so     */
  1785. /*              no indication from user that this is first time is required. */
  1786. /*                                                                           */
  1787. /*              Called only during DriverEntry.                              */
  1788. /*                                                                           */
  1789. /*              The fact that a driver/flavour is returned does not imply    */
  1790. /*              the device is usable - this must be checked by calling       */
  1791. /*              DeviceInit.                                                  */
  1792. /*                                                                           */
  1793. /**PROC-**********************************************************************/
  1794.  
  1795. BOOLean  GetDriverSpec (CHAR *DeviceName,
  1796.                         PCONFIGDATA *pConfigData
  1797.                        )
  1798. {
  1799.   static int DeviceNumber = 0;
  1800.  
  1801.   /* very temporary - until we find out how to read config registry. */
  1802.  
  1803.   if (++DeviceNumber > AT_COUNT)
  1804.     return (FALSE);
  1805.  
  1806.   strcpy (DeviceName, "\\Device\\COMDL$00");
  1807.   DeviceName[strlen(DeviceName)-1] = ((char) ('0' + DeviceNumber));
  1808.   *pConfigData = &ConfigData[DeviceNumber-1];
  1809.   return(TRUE);
  1810.  
  1811. }
  1812.  
  1813. /**PROC+**********************************************************************/
  1814. /*                                                                           */
  1815. /* Name         GetV24Input  (                                                  */
  1816. /*                            PDX pDX                                        */
  1817. /*                           );                                              */
  1818. /*                                                                           */
  1819. /* Purpose      Interpret pin inputs as presented by SDLC cards and stuff    */
  1820. /*              into IR fields                                               */
  1821. /*                                                                           */
  1822. /* Params   IN  pDX - the device extension                                   */
  1823. /*                                                                           */
  1824. /* Return Value None                                                         */
  1825. /*                                                                           */
  1826. /**PROC-**********************************************************************/
  1827.  
  1828. void GetV24Input (PDX pDX)
  1829. {
  1830.   UCHAR o;
  1831.  
  1832.   TRACE_EVENT (<GV2);
  1833.  
  1834.   pDX->pIR->V24In = 0;                  /* reset IR value.                   */
  1835.  
  1836.   /***************************************************************************/
  1837.   /* Reset the 'modem status changed' bit because after we read this         */
  1838.   /* hasn't changed                                                          */
  1839.   /***************************************************************************/
  1840.  
  1841.   WR_N_DELAY (pDX->ADAPTERBASE+AR_8255B,
  1842.               IO_IN (pDX->ADAPTERBASE+AR_8255B) & CAST(~8,UCHAR));
  1843.                                          /* 8 = modem status changed          */
  1844.  
  1845.   /***************************************************************************/
  1846.   /* Read the 8255 Port C settings to get the current state of Test          */
  1847.   /***************************************************************************/
  1848.  
  1849.   if (BITSOFF(IO_IN (pDX->ADAPTERBASE+AR_8255C), 0x40))
  1850.   {
  1851.     pDX->pIR->V24In |= IR_IV24Test;    /* &40 = 0 => Test is Active         */
  1852.   }
  1853.  
  1854.   /***************************************************************************/
  1855.   /* Read the 8255 Port A settings.                                          */
  1856.   /***************************************************************************/
  1857.  
  1858.   o = (IO_IN (pDX->ADAPTERBASE+AR_8255A));
  1859.  
  1860.   if (!(o&1))                          /* &1=0 implies RI on at interface    */
  1861.   {
  1862.     pDX->pIR->V24In |= IR_IV24RI;
  1863.   }
  1864.   if (!(o&2))                          /* &2=0 implies DCD on at interface   */
  1865.   {
  1866.     pDX->pIR->V24In |= IR_IV24DCD;
  1867.   }
  1868.   if (!(o&8))                          /* &8=0 implies CTS on at interface   */
  1869.   {
  1870.     pDX->pIR->V24In |= IR_IV24CTS;
  1871.   }
  1872.  
  1873.   /***************************************************************************/
  1874.   /* Used to do the 8273 Port A Reading to get hold of DSR here.  There are  */
  1875.   /* slight problems with doing that                                         */
  1876.   /* - the 8273 can get upset if given three commands at once (e.g Rx, Tx    */
  1877.   /*    AND CmdStringReadPortA) (this is surmountable)                       */
  1878.   /***************************************************************************/
  1879.  
  1880.   if (pDX->RxFSMCurState NE RxFSMStateReady || /* not receiving ... or       */
  1881.       pDX->TxFSMCurState EQ TxFSMStateIdle)    /* transmitter idle           */
  1882.   {
  1883.     pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
  1884.   }
  1885.  
  1886.   if (pDX->LastPortA & 4)               /* is the DSR bit set???             */
  1887.   {
  1888.     pDX->pIR->V24In |= IR_IV24DSR;
  1889.   }
  1890.   TRACE_EVENT (GV2>);
  1891.  
  1892. }
  1893.  
  1894. /*****************************************************************************/
  1895. /*                                                                           */
  1896. /* Name         InitialiseAdapter                                            */
  1897. /*                                                                           */
  1898. /* Purpose      Initialises and checks the hardware for a link.              */
  1899. /*                                                                           */
  1900. /* Params    IN pDX, plus Synchronised, plus interrupt routines set up       */
  1901. /*                                                                           */
  1902. /* Return Value False on failure, plus SynchInformation set                  */
  1903. /*                                                                           */
  1904. /*****************************************************************************/
  1905.  
  1906. BOOLean InitialiseAdapter (PDX pDX)
  1907. {
  1908.   BOOLean rc;
  1909.  
  1910.   TRACE_EVENT (<InA);
  1911.  
  1912.   /***************************************************************************/
  1913.   /* Resetting the adapter and check that it accepts commands.  Then call    */
  1914.   /* the link options handler to set it up in the default mode.              */
  1915.   /***************************************************************************/
  1916.  
  1917.    AdapterReset(pDX);
  1918.  
  1919.   /***************************************************************************/
  1920.   /* The adapter is now primed and ready to go.  Set up a default link       */
  1921.   /* characteristics configuration and call link set-up.  The link set-up    */
  1922.   /* routine SetLinkConfig returns carry set if problems occur.              */
  1923.   /***************************************************************************/
  1924.  
  1925.   pDX->LinkMaxFrameSize = DEFAULT_FRAME_SIZE;
  1926.   pDX->LinkOptionsByte = 0;
  1927.  
  1928.   if (SetLinkConfig(pDX))
  1929.   {
  1930.     SetV24Output (pDX);
  1931.     GetV24Input (pDX);
  1932.     rc = TRUE;                          /* OK return code                    */
  1933.   }
  1934.   else
  1935.   {
  1936.     SynchTerminateAdapter(pDX);
  1937.     pDX->Information = IO_ERR_HARDWARE_INIT_FAILURE;
  1938.     rc = FALSE;
  1939.     TRACE_EVENT (HwIF);
  1940.     TRACE_RC(rc);
  1941.   }
  1942.  
  1943.   TRACE_EVENT (InA>);
  1944.   return (rc);
  1945. }
  1946.  
  1947. /*****************************************************************************/
  1948. /*                                                                           */
  1949. /* Name         IoctlAbortReceiver                                           */
  1950. /*                                                                           */
  1951. /* Purpose      Abort Receiver IOCtl Processor                               */
  1952. /*                                                                           */
  1953. /* Params    IN pDX                                                          */
  1954. /*                                                                           */
  1955. /*          OUT Requested function is processed. No return code              */
  1956. /*                                                                           */
  1957. /*****************************************************************************/
  1958.  
  1959. void IoctlAbortReceiver (PDX pDX)
  1960. {
  1961.   TRACE_EVENT ([IAR);
  1962.   RxFSMEvent (pDX, RxFSMInputStop);     /* terminate with extreme prejudice  */
  1963.  
  1964.   /***************************************************************************/
  1965.   /* Then reset the buffer pointers, discarding all the data in the receive  */
  1966.   /* buffer.                                                                 */
  1967.   /***************************************************************************/
  1968.  
  1969.   RCVINFO_INIT(pDX);
  1970.   TRACE_EVENT (IAR]);
  1971. }
  1972.  
  1973. /*****************************************************************************/
  1974. /*                                                                           */
  1975. /* Name         IoctlAbortTransmitter                                        */
  1976. /*                                                                           */
  1977. /* Purpose      Abort Transmitter IOCtl Processor                            */
  1978. /*                                                                           */
  1979. /* Params    IN pDX                                                          */
  1980. /*                                                                           */
  1981. /*          OUT None                                                         */
  1982. /*                                                                           */
  1983. /*****************************************************************************/
  1984.  
  1985. void IoctlAbortTransmitter (PDX pDX)
  1986. {
  1987.   TRACE_EVENT ([IAT);
  1988.   /***************************************************************************/
  1989.   /* First stop the transmitter (if it is running).                          */
  1990.   /***************************************************************************/
  1991.  
  1992.   TxFSMEvent (pDX, TxFSMInputStop);
  1993.  
  1994.   /*0025****************************************************************/
  1995.   /*0025* Clear the underrun count.                                    */
  1996.   /*0025****************************************************************/
  1997.  
  1998.   pDX->TxConsecutiveUnderrunCount = 0;
  1999.  
  2000.   /***************************************************************************/
  2001.   /* Then reset the transmit buffer pointers, discarding all the data in the */
  2002.   /* buffer.                                                                 */
  2003.   /***************************************************************************/
  2004.  
  2005.   pDX->TxNextToTransmit = 0;
  2006.   pDX->TxNextToBuffer   = 0;
  2007.  
  2008.   /*0025**********************************************************************/
  2009.   /*0025* Set up the maximum buffer size and the interface record            */
  2010.   /*0025* 'initialisation' buffer size.                                      */
  2011.   /*0025**********************************************************************/
  2012.  
  2013.   pDX->TxStartUnusedArea = SENDBUF_SIZE;
  2014.   pDX->pIR->TxMaxFrSizeNow = INIT_MAXFRSIZENOW;
  2015.   XTRACE_ACTION (Tz, pDX->pIR->TxMaxFrSizeNow);
  2016.   TRACE_EVENT (IAT]);
  2017. }
  2018.  
  2019. /*****************************************************************************/
  2020. /*                                                                           */
  2021. /* Name         IoctlSetInterfaceRecord                                      */
  2022. /*                                                                           */
  2023. /* Purpose      / *IRMdl?* / Obsolete                                          */
  2024. /*              Set Interface Record Address handler                         */
  2025. /*                                                                           */
  2026. /* Params    IN pDX                                                          */
  2027. /*              Implicit: the input buffer address (IrpSp->InputBufferLength */
  2028. /*                      + Irp->AssociatedIrp->SystemBuffer) describes the    */
  2029. /*                      interface record                                     */
  2030. /*                                                                           */
  2031. /*          OUT None                                                         */
  2032. /*                                                                           */
  2033. /* Side Effect  pDX->IoctlRetStatus & Information                            */
  2034. /*                                                                           */
  2035. /* Return Value void                                                         */
  2036. /*                                                                           */
  2037. /*****************************************************************************/
  2038.  
  2039. //void IoctlSetInterfaceRecord (PDX pDX)
  2040. //{
  2041. //  PIRP          pIrp         = pDX->IoctlCurrentIrp;
  2042. //  PIO_STACK_LOCATION
  2043. //                pIrpSp       = IoGetCurrentIrpStackLocation(pIrp);
  2044. //
  2045. //  TRACE_EVENT ([IoI);
  2046. //
  2047. //  /***************************************************************************/
  2048. //  /* The old story: allocate an MDL, probe and lock, map to system address   */
  2049. //  /* space and save the resulting system address in pIR.                     */
  2050. //  /*                                                                         */
  2051. //  /* Free up Mdl and unlock pages if this is a subsequent call.              */
  2052. //  /***************************************************************************/
  2053. //
  2054. //  if (pDX->pIRMdl != NULL)
  2055. //  {
  2056. //    /*************************************************************************/
  2057. //    /* Protect ourselves from bozo users calling IoctlSetInterfaceRecrd twice*/
  2058. //    /*************************************************************************/
  2059. //    ASSERT (pDX->pIR != NULL);
  2060. //    MmUnmapLockedPages (pDX->pIR, pDX->pIRMdl);                    /*IRMdl?*/
  2061. //    IoFreeMdl (pDX->pIRMdl);
  2062. //  }
  2063. //
  2064. //  pDX->pIRMdl = IoAllocateMdl(pIrp->AssociatedIrp.SystemBuffer,
  2065. //                              pIrpSp->IRS_INLEN,
  2066. //                              sizeof (IRP),
  2067. //                              FALSE,    /* this is not a secondary buffer    */
  2068. //                              FALSE,    /* no charge to quota                */
  2069. //                              (PIRP)NULL/* not attached to IRP               */
  2070. //                             );
  2071. //
  2072. //  if (pDX->pIRMdl NE NULL)              /* We could do the mapping           */
  2073. //  {
  2074. //    MmProbeAndLockPages (pDX->pIRMdl, KernelMode, IoModifyAccess);
  2075. //
  2076. //    pDX->pIR = MmMapLockedPages(pDX->pIRMdl, KernelMode);
  2077. //    pDX->pIR->RxFrameCount   = 0;
  2078. //    pDX->pIR->TxMaxFrSizeNow = INIT_MAXFRSIZENOW;
  2079. //    pDX->pIR->StatusCount    = 0;
  2080. //    pDX->pIR->V24In          = 0;
  2081. //    pDX->pIR->V24Out         = 0;
  2082. //    RtlZeroMemory (pDX->pIR->StatusArray, sizeof (pDX->pIR->StatusArray));
  2083. //    TRACE_EVENT (pIR_);
  2084. //    TRACE_DWORD (pDX->pIR);
  2085. //    XTRACE_ACTION (Tz, pDX->pIR->TxMaxFrSizeNow);
  2086. //  }
  2087. //  else
  2088. //  {
  2089. //    pDX->pIR = NULL;
  2090. //    pDX->Information    = INFO_CANT_ALLOCATE_MDL;
  2091. //    pDX->IoctlRetStatus = STATUS_INSUFFICIENT_RESOURCES;
  2092. //  }
  2093. //  TRACE_EVENT (IoI]);
  2094. //}
  2095.  
  2096. /*****************************************************************************/
  2097. /*                                                                           */
  2098. /* Name         IoctlSetLinkConfig                                           */
  2099. /*                                                                           */
  2100. /* Purpose      Set Link Characteristics IOCtl Processor                     */
  2101. /*                                                                           */
  2102. /*              Sets the link configuration on the basis of the supplied     */
  2103. /*              parameters.  This routine also aborts any outstanding        */
  2104. /*              activity in case there is a conflict between old and new     */
  2105. /*              parameters (switching to DMA for instance!).                 */
  2106. /*                                                                           */
  2107. /* Params    IN pDX                                                          */
  2108. /*                                                                           */
  2109. /*          OUT                                                              */
  2110. /*                                                                           */
  2111. /* Side Effect  pDX->IoctlRetStatus & Information                            */
  2112. /*                                                                           */
  2113. /*****************************************************************************/
  2114.  
  2115. BOOLean IoctlSetLinkConfig (PDX pDX)
  2116. {
  2117.   PIRP          pIrp         = pDX->IoctlCurrentIrp;
  2118.   PIO_STACK_LOCATION
  2119.                 pIrpSp       = IoGetCurrentIrpStackLocation(pIrp);
  2120.   SLPARMS     *pParms        = pIrp->AssociatedIrp.SystemBuffer;
  2121.   UCHAR         NewOpt       = pParms->SLLinkOptionsByte; /* easier to type  */
  2122.   BOOLean       rc           = FALSE;   /* assume the worst!                 */
  2123.  
  2124.   TRACE_EVENT ([IoC);
  2125.  
  2126.   /***************************************************************************/
  2127.   /* Issue the abort calls to get Tx and Rx synchronised with this.          */
  2128.   /***************************************************************************/
  2129.  
  2130.   IoctlAbortReceiver (pDX);
  2131.   IoctlAbortTransmitter(pDX);
  2132.  
  2133.   /***************************************************************************/
  2134.   /* Read the parameter data.  Check that frame will fit the buffer.         */
  2135.   /***************************************************************************/
  2136.  
  2137.   if (pIrpSp->IRS_INLEN NE sizeof(SLPARMS))
  2138.   {
  2139.     pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
  2140.     pDX->Information = IO_ERR_LINKCHAR_BUF_WRONG_SIZE;
  2141.   }
  2142.   else
  2143.   if (pParms->SLFrameSize < 267)    /* don't really want < 2+6+3+256 bytes!? */
  2144.   {
  2145.     pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
  2146.     pDX->Information = IO_ERR_FRAME_BUF_TOO_SMALL;
  2147.   }
  2148.   else
  2149.   if (pParms->SLFrameSize > 2048)   /* really SDLC frame bigger than 2Kb?    */
  2150.   {
  2151.     pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
  2152.     pDX->Information = IO_ERR_FRAME_BUF_TOO_BIG;
  2153.   }
  2154.   else
  2155.   if (pParms->SLLinkOptionsByte & LinkOption_InternalClock)
  2156.   {
  2157.     /*************************************************************************/
  2158.     /* We have been asked to supply internal clocks (not supported by these  */
  2159.     /* adapters).                                                            */
  2160.     /*************************************************************************/
  2161.  
  2162.     pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
  2163.     pDX->Information = IO_ERR_NO_CLOCKS;
  2164.   }
  2165.   else
  2166.   {
  2167.     pDX->LinkMaxFrameSize = pParms->SLFrameSize;
  2168.  
  2169.     /*************************************************************************/
  2170.     /* Pick up the addresses and put them in the LCB.  Then set General or   */
  2171.     /* specific receive depending on whether the addresses are zero.         */
  2172.     /*************************************************************************/
  2173.  
  2174.     pDX->OurAddress1         = pParms->SLOurAddress1;
  2175.     pDX->OurAddress2         = pParms->SLOurAddress2;
  2176.     pDX->CmdStringReceive[4] = pParms->SLOurAddress1;
  2177.     pDX->CmdStringReceive[5] = pParms->SLOurAddress2;
  2178.  
  2179.     if (pParms->SLOurAddress1 EQ 0 &&
  2180.         pParms->SLOurAddress2 EQ 0)
  2181.     {
  2182.       /***********************************************************************/
  2183.       /* if both addresses are zero, we are SDLC primary and can accept      */
  2184.       /* frames targetted at any address                                     */
  2185.       /***********************************************************************/
  2186.       pDX->CmdStringReceive[0] = 0xC0;  /* set 3-byte General Rx command     */
  2187.       pDX->CmdStringReceive[1] = 2;
  2188.     }
  2189.     else
  2190.     {
  2191.       pDX->CmdStringReceive[0] = 0xC1;  /* set 5-byte Specific Rx command    */
  2192.       pDX->CmdStringReceive[1] = 4;
  2193.     }
  2194.  
  2195.     /*************************************************************************/
  2196.     /* Next, pick up the Link Options and make any necessary changes.        */
  2197.     /*************************************************************************/
  2198.  
  2199.     if (NewOpt & LinkOption_FullDuplex  /* turn off DMA if the link will     */
  2200.         && NewOpt & LinkOption_DMA)     /* be full duplex.                   */
  2201.     {
  2202.       /***********************************************************************/
  2203.       /* Check whether the caller asked for DMA, but we couldn't support it  */
  2204.       /* - return warning error if so.                                       */
  2205.       /***********************************************************************/
  2206.  
  2207.       NewOpt &= ~LinkOption_DMA;
  2208.       pDX->Information = IO_ERR_NO_DMA_FDX; /* but r/c is OK.                */
  2209.     }
  2210.  
  2211.     pDX->LinkOptionsByte = NewOpt;      /* set the new options byte          */
  2212.  
  2213.  
  2214.     /*************************************************************************/
  2215.     /* Clear the statistics data on the IF record if the appl wants to.      */
  2216.     /*************************************************************************/
  2217.  
  2218.     if (NewOpt & LinkOption_ResetStatistics)
  2219.     {                                   /* clear the statistics ??           */
  2220.       RtlZeroMemory (pDX->pIR->StatusArray, sizeof(pDX->pIR->StatusArray));
  2221.       pDX->pIR->StatusCount = 0;
  2222.     }
  2223.  
  2224.     /*************************************************************************/
  2225.     /* Now set the options and start the receiver.                           */
  2226.     /*************************************************************************/
  2227.  
  2228.     if (SetLinkConfig (pDX))            /* call hardware to set options      */
  2229.     {
  2230.       RxFSMEvent (pDX, RxFSMInputStart);/* start receiver if possible        */
  2231.       rc = TRUE;                        /* set good return code              */
  2232.     }
  2233.     else
  2234.     {
  2235.       pDX->IoctlRetStatus = STATUS_DATA_ERROR;
  2236.       pDX->Information    = IO_ERR_HARDWARE_CMD_TIMEOUT_4;
  2237.     }
  2238.   }
  2239.  
  2240.   TRACE_EVENT (IoC]);
  2241.   return(rc);
  2242. }
  2243.  
  2244. /**PROC+**********************************************************************/
  2245. /*                                                                           */
  2246. /* Name         IoctlRxFrame                                                 */
  2247. /*                                                                           */
  2248. /* Purpose      Receive Request processor                                    */
  2249. /*                                                                           */
  2250. /*              Copies next available frame to the application buffer.       */
  2251. /*                                                                           */
  2252. /* Params    IN IRP: buffer length  in Stack->OutputBufferLength (IRS_OUTLEN)*/
  2253. /*                   buffer pointer in UserBuffer                            */
  2254. /*                                                                           */
  2255. /*          OUT Available data, if any                                       */
  2256. /*                                                                           */
  2257. /* Side Effect  pDX->IoctlRetStatus & Information                            */
  2258. /*                                                                           */
  2259. /* Return Value TRUE - ignored                                               */
  2260. /*                                                                           */
  2261. /**PROC-**********************************************************************/
  2262.  
  2263. BOOLean IoctlRxFrame (PDX pDX)
  2264. {
  2265.   PIRP               pIrp         = pDX->IoctlCurrentIrp;
  2266.   PIO_STACK_LOCATION pIrpSp       = IoGetCurrentIrpStackLocation(pIrp);
  2267.   RFD               *pRFD;
  2268.   short              RxLength;
  2269.   UCHAR  *           GiveMeACharPtr;
  2270.  
  2271.   TRACE_EVENT ([IoR);
  2272.  
  2273.   /***************************************************************************/
  2274.   /* Check to see if there are any frames waiting in the buffer.  The ISR    */
  2275.   /* fills the buffer by incrementing the 'head' pointer but stops before it */
  2276.   /* catches up with the 'tail'.                                             */
  2277.   /***************************************************************************/
  2278.  
  2279.   if (RFD_CAN_GET(pDX))          /* then there is data present */
  2280.   {
  2281.     pRFD = &pDX->RcvInfo.RFDArray[pDX->RcvInfo.RFDNextToGet];
  2282.  
  2283.     /*************************************************************************/
  2284.     /* We need to copy the data from our buffer into the user's buffer.      */
  2285.     /* The actual output length goes into the Information field              */
  2286.     /*************************************************************************/
  2287.  
  2288.     RxLength = pRFD->RcvdDataLength;
  2289.     if (CAST(RxLength, ULONG) + 2 > pIrpSp->IRS_OUTLEN)
  2290.     {
  2291.       /***********************************************************************/
  2292.       /* Output buffer not as big as A + C + Data received                   */
  2293.       /***********************************************************************/
  2294.       pDX->IoctlRetStatus = STATUS_BUFFER_TOO_SMALL;
  2295.     }
  2296.     else
  2297.     {
  2298.       ASSERT (RxLength >= 0);           /* n.b. but length = 0 is OK         */
  2299.                                         /* (RR's will have length of 0 in    */
  2300.                                         /* buffer, which we report to  user  */
  2301.                                         /* as length of 0                    */
  2302.  
  2303.       if (RxLength >= 0)                /* != -1 => really something there   */
  2304.       {
  2305.         GiveMeACharPtr = MmMapLockedPages(pIrp->MdlAddress, KernelMode);
  2306.  
  2307.         GiveMeACharPtr[0] = pRFD->SDLCAddressByte;
  2308.         GiveMeACharPtr[1] = pRFD->SDLCControlByte;
  2309.         RtlMoveMemory (&GiveMeACharPtr[2], pRFD->StartAddr, RxLength);
  2310.       }
  2311.     }
  2312.  
  2313.     /*************************************************************************/
  2314.     /* We signal the actual received length back in the IoStatusBlock, via   */
  2315.     /* pDX.                                                                  */
  2316.     /*************************************************************************/
  2317.     pDX->Information = RxLength+2;
  2318.  
  2319.     RFD_GOT(pDX);                   /* release the buffer we got             */
  2320.  
  2321.     /*************************************************************************/
  2322.     /* Lastly decrement the count of received frames available in the shared */
  2323.     /* data area.                                                            */
  2324.     /*************************************************************************/
  2325.  
  2326.     pDX->pIR->RxFrameCount--;
  2327.   }
  2328.   else
  2329.   {
  2330.     pDX->Information = 0;
  2331.     TRACE_EVENT (IoRN);
  2332.   }
  2333.  
  2334.   TRACE_EVENT (IoR]);
  2335.   return (TRUE);
  2336. }
  2337.  
  2338. /*****************************************************************************/
  2339. /*                                                                           */
  2340. /* Name         IoctlSetV24Output                                            */
  2341. /*                                                                           */
  2342. /* Purpose      Handles the IoCtl to set the V24 Output                      */
  2343. /*                                                                           */
  2344. /* Params    IN pDX                                                          */
  2345. /*              Implicit input: V24Out byte in IR is what is to be pumped out*/
  2346. /*                                                                           */
  2347. /*          OUT TRUE                                                         */
  2348. /*                                                                           */
  2349. /* Side Effect  pDX->IoctlRetStatus & Information                            */
  2350. /*                                                                           */
  2351. /*****************************************************************************/
  2352.  
  2353. BOOLean IoctlSetV24Output (PDX pDX)
  2354. {
  2355.   TRACE_EVENT ([IVO);
  2356. // temporary hack !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2357.   pDX->pIR->V24Out = *(CAST (pDX->IoctlCurrentIrp->UserBuffer, UCHAR *));
  2358. // temporary hack !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2359.  
  2360.   if (!SetV24Output(pDX))                         /* call hardware processor */
  2361.   {
  2362.     return (FALSE);
  2363.   }
  2364.  
  2365.   TRACE_EVENT (IVO]);
  2366.   return (TRUE);
  2367. }
  2368.  
  2369. /*****************************************************************************/
  2370. /*                                                                           */
  2371. /* Name         IoctlTxFrame                                                     */
  2372. /*                                                                           */
  2373. /* Purpose      Transmit frame request handler.  Puts frames into the Tx     */
  2374. /*              buffer ready for the Tx FSM to use.                          */
  2375. /*                                                                           */
  2376. /*              Transmit Request Processor.                                  */
  2377. /*                                                                           */
  2378. /* Params    IN pIrp parameters point to request packet data and length      */
  2379. /*                                                                           */
  2380. /*          OUT Data transferred to Tx buffer ready to send.                 */
  2381. /*              Transmitter FSM kicked.                                      */
  2382. /*                                                                           */
  2383. /* Side Effect  pDX->IoctlRetStatus & Information                            */
  2384. /*                                                                           */
  2385. /*****************************************************************************/
  2386.  
  2387. BOOLean IoctlTxFrame (PDX pDX)
  2388. {
  2389.   ULONG              BufferSpaceNeeded;
  2390.   ULONG              BufferSpaceAvailable;
  2391.   PIRP               pIrp         = pDX->IoctlCurrentIrp;
  2392.   PIO_STACK_LOCATION pIrpSp       = IoGetCurrentIrpStackLocation(pIrp);
  2393.   BOOLean            rc           = TRUE;   /* normally OK                   */
  2394.  
  2395.   TRACE_EVENT ([IoT);
  2396.  
  2397.   BufferSpaceNeeded = pIrpSp->IRS_OUTLEN
  2398.                       + 2;              /* allow for frame length header     */
  2399.  
  2400.   XTRACE_ACTION (Tn, BufferSpaceNeeded);
  2401.   XTRACE_ACTION (Tx, pDX->LinkMaxFrameSize);
  2402.   XTRACE_ACTION (Tb, pDX->TxNextToBuffer);
  2403.   XTRACE_ACTION (Tt, pDX->TxNextToTransmit);
  2404.  
  2405.   if (CAST(pIrpSp->IRS_OUTLEN, int) < 2)
  2406.   {
  2407.     /*************************************************************************/
  2408.     /* The minimum frame size is 2                                           */
  2409.     /*************************************************************************/
  2410.  
  2411.      pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
  2412.      pDX->Information    = IO_ERR_TX_FRAME_TOO_SMALL;
  2413.      rc = FALSE;
  2414.      TRACE_RC(rc);
  2415.      return(rc);
  2416.   }
  2417.  
  2418.   if (CAST(pIrpSp->IRS_OUTLEN, int) > pDX->LinkMaxFrameSize)
  2419.   {
  2420.     /*************************************************************************/
  2421.     /* The frame is bigger than the maximum specified                        */
  2422.     /*************************************************************************/
  2423.  
  2424.      pDX->IoctlRetStatus = STATUS_INVALID_PARAMETER;
  2425.      pDX->Information    = IO_ERR_TX_FRAME_TOO_BIG;
  2426.      rc = FALSE;
  2427.      TRACE_RC(rc);
  2428.      return(rc);
  2429.   }
  2430.  
  2431.   /***************************************************************************/
  2432.   /* Check to see if there is room for the data in the transmit buffer.      */
  2433.   /* This code fills the buffer by incrementing the 'ToTransmit' pointer but */
  2434.   /* stops before it catches up with the 'tail'.  The ISR takes frames from  */
  2435.   /* the tail pointer, incrementing it until it matches ToTransmit.          */
  2436.   /***************************************************************************/
  2437.  
  2438.   /***************************************************************************/
  2439.   /* The ToBuffer and ToTransmit pointers could be anywhere.  This code      */
  2440.   /* checks for ToTransmit < ToBuffer and works out the difference -> AX.    */
  2441.   /* If the ToTransmit is greater than the ToBuffer, there could be space at */
  2442.   /* either end if the buffer - the top end is checked and, if too small,    */
  2443.   /* the ToTransmit is moved round to the start and then checked as          */
  2444.   /* ToTransmit < ToBuffer.                                                  */
  2445.   /***************************************************************************/
  2446.  
  2447.   if (pDX->TxNextToBuffer >= pDX->TxNextToTransmit)
  2448.   {                                     /* ToTransmit is in front of ToBuffer*/
  2449.     /*************************************************************************/
  2450.     /* The free space is at the end of the buffer.  If this is too small,    */
  2451.     /* set the 'end' for the ISR to the current ToTransmit and then move     */
  2452.     /* ToTransmit round to the front.  Note: we don't go up to SENDBUF_SIZE  */
  2453.     /* because the  TxStartUnusedArea must start on that                     */
  2454.     /*************************************************************************/
  2455.  
  2456.     BufferSpaceAvailable = SENDBUF_SIZE - 1 - pDX->TxNextToBuffer;
  2457.     if (BufferSpaceNeeded > BufferSpaceAvailable)
  2458.                                         /* not enough space at the end ?     */
  2459.     {
  2460.       pDX->TxStartUnusedArea = pDX->TxNextToBuffer;
  2461.                                         /* ISR will wrap at this point       */
  2462.       pDX->TxNextToBuffer    = 0;
  2463.       BufferSpaceAvailable   = pDX->TxNextToTransmit-1;/* free up to bfr area*/
  2464.  
  2465.       XTRACE_ACTION (Tu, pDX->TxStartUnusedArea);
  2466.       XTRACE_ACTION (Tb, pDX->TxNextToBuffer);
  2467.       XTRACE_ACTION (Ta, BufferSpaceAvailable);
  2468.     }
  2469.   }
  2470.   else
  2471.   {
  2472.     /*************************************************************************/
  2473.     /* the free space is from NextToTransmit up to NextToBuffer              */
  2474.     /*************************************************************************/
  2475.  
  2476.     BufferSpaceAvailable   = pDX->TxNextToBuffer - 1 - pDX->TxNextToTransmit;
  2477.     XTRACE_ACTION (Ta, BufferSpaceAvailable);
  2478.   }
  2479.  
  2480.   if (BufferSpaceAvailable >= BufferSpaceNeeded)
  2481.   {
  2482.     /*************************************************************************/
  2483.     /* The 'Max Tx Frame is initialised to be a little less than half the    */
  2484.     /* total size of the transmit buffer and is decremented by half the size */
  2485.     /* of each frame put in (rounded UP).  It is kept at half because the    */
  2486.     /* bfr can get split into two pieces and we need a contiguous area.      */
  2487.     /*************************************************************************/
  2488.  
  2489.     pDX->pIR->TxMaxFrSizeNow -= (BufferSpaceNeeded + 1) >> 1;
  2490.     XTRACE_ACTION (Tz, pDX->pIR->TxMaxFrSizeNow);
  2491.     pDX->pSendBuf [pDX->TxNextToBuffer]   = LOBYTE(BufferSpaceNeeded-2);
  2492.     pDX->pSendBuf [pDX->TxNextToBuffer+1] = HIBYTE(BufferSpaceNeeded-2);
  2493.                                                 /* set length to data length */
  2494.                                                 /* (-2 => less length itself)*/
  2495.     RtlMoveMemory (&(pDX->pSendBuf[pDX->TxNextToBuffer+2]),
  2496.                    pIrp->UserBuffer,
  2497.                    BufferSpaceNeeded-2);
  2498.  
  2499.     /*************************************************************************/
  2500.     /* Now set up the new buffer ToTransmit position.                        */
  2501.     /*************************************************************************/
  2502.  
  2503.     pDX->TxNextToBuffer += BufferSpaceNeeded;
  2504.     XTRACE_ACTION (Tb, pDX->TxNextToBuffer);
  2505.     ASSERT (pDX->TxNextToBuffer < SENDBUF_SIZE);
  2506.  
  2507.     /*************************************************************************/
  2508.     /* Kick the Transmit FSM to start it off.                                */
  2509.     /*************************************************************************/
  2510.  
  2511.     TxFSMEvent (pDX, TxFSMInputStart);
  2512.  
  2513.     // and returned status is TRUE;
  2514.   }
  2515.   else
  2516.   {
  2517.     /*************************************************************************/
  2518.     /* There is no room for the frame - return an error.                     */
  2519.     /*************************************************************************/
  2520.  
  2521.      pDX->IoctlRetStatus = STATUS_BUFFER_TOO_SMALL;
  2522.      pDX->Information    = IO_ERR_TX_BUFFER_FULL;
  2523.      rc = FALSE;
  2524.      TRACE_RC(rc);
  2525.   }
  2526.  
  2527.   TRACE_EVENT (IoT]);
  2528.  
  2529.   return (rc);
  2530.  
  2531. }
  2532.  
  2533. /*****************************************************************************/
  2534. /*                                                                           */
  2535. /* Name         RxFSMActionInvalid                                           */
  2536. /*                                                                           */
  2537. /* Purpose      Error input to FSM                                           */
  2538. /*                                                                           */
  2539. /*              This routine should never be called as it implies an         */
  2540. /*              'impossible state/input combination.  This is taken to mean  */
  2541. /*              that adapter status has been incorrectly reported and is     */
  2542. /*              treated as a hardware error.                                 */
  2543. /*                                                                           */
  2544. /* Params    IN pDX                                                          */
  2545. /*                                                                           */
  2546. /*          OUT Error processing started by RQ FSM input                     */
  2547. /*                                                                           */
  2548. /*****************************************************************************/
  2549.  
  2550. void RxFSMActionInvalid (PDX pDX)
  2551. {
  2552.   TRACE_EVENT (RAI:);
  2553.  
  2554.   pDX->pIR->StatusArray[SA_HardwareError]++;
  2555.   pDX->pIR->StatusCount ++;
  2556.   pDX->DPCAction |= DPC_ACTION_PULSE;
  2557.  
  2558.   TRACE_EVENT (RAI;);
  2559. }
  2560.  
  2561. /*****************************************************************************/
  2562. /*                                                                           */
  2563. /* Name         RxFSMActionRestart                                           */
  2564. /*                                                                           */
  2565. /* Purpose      Coming back after having held rx so transmitter can go       */
  2566. /*              so - we can switch buffers so DMA can run for the whole buf  */
  2567. /*                                                                           */
  2568. /* Params    IN pDX                                                          */
  2569. /*                                                                           */
  2570. /*              Implicit input: that when the receiver was stopped that the  */
  2571. /*              'NowBeingPut' RFD for this adapter was allocated and init-   */
  2572. /*              ialised properly.  So this is just a 'start reciver'.        */
  2573. /*                                                                           */
  2574. /*          OUT Receiver started                                             */
  2575. /*                                                                           */
  2576. /*                                                                           */
  2577. /*****************************************************************************/
  2578.  
  2579. void RxFSMActionRestart (PDX pDX)
  2580. {
  2581.   RFD     * pRFD = & pDX->RcvInfo.RFDArray[pDX->RcvInfo.RFDNowBeingPut];
  2582.  
  2583.   TRACE_EVENT (RRs:);
  2584.  
  2585.   pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
  2586.  
  2587.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  2588.   {
  2589.     StopDMA (pDX);
  2590.     XASSERT (!pDX->DMAIsActive);
  2591.  
  2592.     /*************************************************************************/
  2593.     /* only worry about this if we using DMA and if other buffer not in use  */
  2594.     /*************************************************************************/
  2595.     if (!(RCVBUF_INUSE(pRFD->BufPtr->OtherBuffer)))
  2596.     {
  2597.       /* use other buffer */
  2598.       pRFD->BufPtr    = pRFD->BufPtr->OtherBuffer;
  2599.       pRFD->StartIndex= 0;
  2600.       pRFD->StartAddr = &pRFD->BufPtr->Data[0];
  2601.     }
  2602.   }
  2603.   RxFSMActionStart (pDX);
  2604.   TRACE_EVENT (RRs;);
  2605. }
  2606.  
  2607. /*****************************************************************************/
  2608. /*                                                                           */
  2609. /* Name         RxFSMActionStart                                             */
  2610. /*                                                                           */
  2611. /* Purpose      Starts the Receiver and DMA (if configured).                 */
  2612. /*                                                                           */
  2613. /* Params    IN pDX                                                          */
  2614. /*                                                                           */
  2615. /*              Implicit input: that when the receiver was stopped that the  */
  2616. /*              'NowBeingPut' RFD for this adapter was allocated and init-   */
  2617. /*              ialised properly.  So this is just a 'start reciver'.        */
  2618. /*                                                                           */
  2619. /*          OUT Receiver started                                             */
  2620. /*                                                                           */
  2621. /*                                                                           */
  2622. /*****************************************************************************/
  2623.  
  2624. void RxFSMActionStart (PDX pDX)
  2625. {
  2626.   RFD     * pRFD = & pDX->RcvInfo.RFDArray[pDX->RcvInfo.RFDNowBeingPut];
  2627.   int       AvailableByteCount = RCVDATABUF_SIZE - 1 - pRFD->StartIndex;
  2628.                                         /* allocate all the rest of the buffr*/
  2629.                                         /* This really is the available bytes*/
  2630.   USHORT    CmdByteCount = CAST (AvailableByteCount - 2, USHORT);
  2631.                                         /* number of bytes to command 8273   */
  2632.   TRACE_EVENT (RSt:);
  2633.  
  2634.   XASSERT (AvailableByteCount >= CAST (pDX->LinkMaxFrameSize, int));
  2635.                                         /* frame must fit into rest of buffer*/
  2636.                                         /* or previous code screwed up       */
  2637.   XTRACE_ACTION (Ra, AvailableByteCount);
  2638.  
  2639.   /***************************************************************************/
  2640.   /* Prime the DMA if necessary.                                             */
  2641.   /***************************************************************************/
  2642.  
  2643.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  2644.   {
  2645.     if (!pDX->DMAIsActive)
  2646.     {
  2647.       /***********************************************************************/
  2648.       /* If the DMA is already running we just leave it running.  Otherwise  */
  2649.       /* need to start it                                                    */
  2650.       /***********************************************************************/
  2651.       PHYSICAL_ADDRESS L;
  2652.  
  2653.       L = pRFD->BufPtr->DataPhysAddr;
  2654.       L.LowPart += (ULONG) pRFD->StartIndex;
  2655.       StartDMA (pDX,
  2656.                 L,
  2657.                 CmdByteCount,           /* should be one less, but we've left*/
  2658.                                         /* two bytes slop above anyway       */
  2659.                 DMACmdWrite
  2660.              );
  2661.     }
  2662.     XASSERT (pDX->DMAIsActive);
  2663.   }
  2664.   else
  2665.   {
  2666.     pDX->pRxPIOData = pRFD->StartAddr;
  2667.     XTRACE_EVENT (RPIO);
  2668.     XTRACE_DWORD (pDX->pRxPIOData);
  2669.   }
  2670.  
  2671.   pDX->CmdStringReceive[2] = LOBYTE(CmdByteCount);
  2672.   pDX->CmdStringReceive[3] = HIBYTE(CmdByteCount);
  2673.  
  2674.   Write8273Cmd (pDX, pDX->CmdStringReceive);
  2675.  
  2676.   TRACE_EVENT (RSt;);
  2677. }
  2678.  
  2679. /****************************************************************************/
  2680. /*                                                                          */
  2681. /* Name         RxFSMActionStop                                                    */
  2682. /*                                                                          */
  2683. /* Purpose      Stops the Receiver and DMA (if configured).                 */
  2684. /*                                                                          */
  2685. /* Params    IN pDX                                                         */
  2686. /*                                                                          */
  2687. /*          OUT Receiver stopped                                            */
  2688. /*                                                                          */
  2689. /****************************************************************************/
  2690.  
  2691. void RxFSMActionStop (PDX pDX)
  2692. {
  2693.   TRACE_EVENT (RSo:);
  2694.  
  2695.   /*********************************************************************/
  2696.   /* Check whether DMA is supported and kill the DMA Channel if so.    */
  2697.   /*********************************************************************/
  2698.  
  2699.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  2700.   {
  2701.     StopDMA (pDX);
  2702.     XASSERT (!pDX->DMAIsActive);
  2703.   }
  2704.  
  2705.   /*********************************************************************/
  2706.   /* Issue a Disable command to the 8273.                              */
  2707.   /*********************************************************************/
  2708.  
  2709.   Write8273Cmd (pDX, pDX->CmdStringDisableReceiver);
  2710.  
  2711.   /***************************************************************************/
  2712.   /* Following IO_DELAY is an attempt to prevent a hang reading port A in    */
  2713.   /* this situation                                                          */
  2714.   /***************************************************************************/
  2715.   IO_DELAY(5L);
  2716.   pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
  2717.  
  2718.   TRACE_EVENT (RSo;);
  2719. }
  2720.  
  2721. /****************************************************************************/
  2722. /*                                                                          */
  2723. /* Name         RxFSMActionRcvError                                                    */
  2724. /*                                                                          */
  2725. /* Purpose      Updates the received data statistics and restarts the Rcvr  */
  2726. /*                                                                          */
  2727. /*              Carries out end-of-frame processing on error results.       */
  2728. /*                                                                          */
  2729. /* Params    IN BX -> error result from the 8273                            */
  2730. /*                                                                          */
  2731. /*          OUT Updated Rx stats - receiver restarted.                      */
  2732. /*                                                                          */
  2733. /****************************************************************************/
  2734.  
  2735. void RxFSMActionRcvError (PDX pDX)
  2736. {
  2737.   /***************************************************************************/
  2738.   /* Clear the top nibble of result so we can detect non-octet boundary errs */
  2739.   /***************************************************************************/
  2740.  
  2741.   UCHAR   ResultCode = CAST(pDX->RxResultBuffer[0] & 0x0F, UCHAR);
  2742.  
  2743.   static
  2744.   USHORT  ErrorMapArray[] =             /* f: 8273code -> index in StatusArry*/
  2745.   {
  2746.      /*  0General       */ SA_Spare + 256,      /* +256->stop receiver       */
  2747.      /*  1Selective     */ SA_Spare + 256,
  2748.      /*  2<unused>      */ SA_HardwareError,    /* shouldn't be generated    */
  2749.      /*  3CRC           */ SA_CRC_Error + 256,
  2750.      /*  4Abort         */ SA_RxAbort + 256,
  2751.      /*  5Idle          */ 0,                   /* don't use                 */
  2752.      /*  6EOP           */ SA_Spare,
  2753.      /*  7Short         */ SA_RxFrameTooShort + 256,
  2754.      /*  8DMAOverrun    */ SA_RxOverrun,
  2755.      /*  9BufO          */ SA_RxFrameTooBig,
  2756.      /* 10RLSD          */ SA_DCDDrop,
  2757.      /* 11RxIntOverrun  */ SA_HardwareError,
  2758.      /* 12 tx           */ SA_HardwareError,
  2759.      /* 13 tx           */ SA_HardwareError,
  2760.      /* 14 tx           */ SA_HardwareError,
  2761.      /* 15 tx           */ SA_HardwareError,    /* 15 for 0x0F & value       */
  2762.   };
  2763.  
  2764.   XASSERT (ResultCode < 12);
  2765.   XTRACE_ACTION (Rm, ErrorMapArray[ResultCode]);
  2766.  
  2767.   /***************************************************************************/
  2768.   /* Filter out 'idle' indications before going through checks               */
  2769.   /***************************************************************************/
  2770.  
  2771.   if (ResultCode NE ARxR_ErrIdle)       /* no StopRequired - idle stop Rcvr  */
  2772.   {
  2773.     /*************************************************************************/
  2774.     /* Increment the statistics and set the flag to pulse event              */
  2775.     /*************************************************************************/
  2776.  
  2777.     pDX->pIR->StatusArray[LOBYTE(ErrorMapArray[ResultCode])]++;
  2778.     pDX->pIR->StatusCount++;
  2779.     pDX->DPCAction |= DPC_ACTION_PULSE;
  2780.   }
  2781.  
  2782.   /*********************************************************************/
  2783.   /* Check whether DMA is supported and kill the DMA Channel if so.    */
  2784.   /*********************************************************************/
  2785.  
  2786.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  2787.   {
  2788.     StopDMA (pDX);
  2789.     XASSERT (!pDX->DMAIsActive);
  2790.   }
  2791.  
  2792.   /***************************************************************************/
  2793.   /* For those situations that need it (i.e.  where the error has left the   */
  2794.   /* receiver active), stop the receiver.  As a result, the receiver will    */
  2795.   /* always be stopped after an error.  This is just being paranoid -        */
  2796.   /* shouldn't really need to.                                               */
  2797.   /***************************************************************************/
  2798.  
  2799.   if (HIBYTE(ErrorMapArray[ResultCode]))        /* high byte->stop required  */
  2800.   {
  2801.     RxFSMActionStop (pDX);
  2802.   }
  2803.  
  2804.   /***************************************************************************/
  2805.   /* Now call the action routine to restart the receiver.                    */
  2806.   /***************************************************************************/
  2807.  
  2808.   RxFSMActionStart (pDX);
  2809.  
  2810. }
  2811.  
  2812. /*****************************************************************************/
  2813. /*                                                                           */
  2814. /* Name         RxFSMActionRcvOK                                             */
  2815. /*                                                                           */
  2816. /* Purpose      Updates the Receiver buffer data to reflect new data, does   */
  2817. /*              some statistics adjustment and kicks the Rx sema4.           */
  2818. /*                                                                           */
  2819. /*              Carries out end-of-received frame processing.                */
  2820. /*                                                                           */
  2821. /* Params    IN pDX                                                          */
  2822. /*              Implicit:pDX->ResultBuffer has all results                   */
  2823. /*                          [0] = OK result code                             */
  2824. /*                          [1] = Length (lo)                                */
  2825. /*                          [2] = Length (hi)                                */
  2826. /*                          [3] = Address                                    */
  2827. /*                          [4] = Control                                    */
  2828. /*                                                                           */
  2829. /*          OUT Updated Rx buffer and stats - receiver restarted.            */
  2830. /*                                                                           */
  2831. /*****************************************************************************/
  2832.  
  2833. void RxFSMActionRcvOK (PDX pDX)
  2834. {
  2835.                                         /* this is the 'Old' one             */
  2836.                                         /* New NowBeingPut                   */
  2837.   BOOLean       CanMoveOn = TRUE;       /* won't be true if no more RFDs OR  */
  2838.                                         /* no space in this buffer and other */
  2839.                                         /* buffer in use                     */
  2840.   BOOLean       MustStopReceiver = TRUE;
  2841.   short         NewNBP = CAST((pDX->RcvInfo.RFDNowBeingPut+1) % RFDARRAY_SIZE,
  2842.                               short);
  2843.   RFD         * pNewRFD= & pDX->RcvInfo.RFDArray[NewNBP];
  2844.   USHORT        RcvdLength;
  2845.   RFD         * pRFD   = & pDX->RcvInfo.RFDArray[pDX->RcvInfo.RFDNowBeingPut];
  2846.  
  2847.   TRACE_EVENT (ROk:);
  2848.   XTRACE_OBJECT(Rp, (*pRFD));
  2849.   XTRACE_DWORD (pRFD);
  2850.   XTRACE_OBJECT(Rb, (*(pRFD->BufPtr)));
  2851.   XTRACE_ACTION(Rs, pRFD->StartIndex);
  2852.  
  2853.   /***************************************************************************/
  2854.   /* First, copy results into existing RFD                                   */
  2855.   /***************************************************************************/
  2856.  
  2857.   XASSERT (pRFD->RcvdDataLength EQ -1);     /* this buffer hasn't been 'filled'  */
  2858.  
  2859.   pRFD->SDLCAddressByte = pDX->RxResultBuffer[3];
  2860.   pRFD->SDLCControlByte = pDX->RxResultBuffer[4];
  2861.   pRFD->RcvdDataLength  = MAKEUSHORT (pDX->RxResultBuffer[1],
  2862.                                       pDX->RxResultBuffer[2]);
  2863.   RcvdLength = pRFD->RcvdDataLength;
  2864.   XTRACE_ACTION (Rl,RcvdLength);
  2865.  
  2866.   /***************************************************************************/
  2867.   /* Double-check the length the 8273 tells us compared to what we rcvd on   */
  2868.   /* the interrupt side                                                      */
  2869.   /***************************************************************************/
  2870.  
  2871. #ifdef XDEBUG
  2872.  
  2873.   if (BITSOFF(pDX->GrabbedResources,GRABBEDRESOURCE_GOTDMA))
  2874.     XASSERT (CAST(pRFD->RcvdDataLength, int) EQ
  2875.                                           (pDX->pRxPIOData - pRFD->StartAddr));
  2876. #endif
  2877.  
  2878.   /***************************************************************************/
  2879.   /* Now figure out a) if we can fit next frame into this buffer, and b)     */
  2880.   /* failing that if we can start using the other buffer                     */
  2881.   /***************************************************************************/
  2882.  
  2883.   if (NewNBP EQ pDX->RcvInfo.RFDNextToGet)
  2884.   {
  2885.     CanMoveOn = FALSE;                  /* can't wrap round onto next to get */
  2886.   }
  2887.   else
  2888.   {
  2889.  
  2890.     /*************************************************************************/
  2891.     /* Set up the new startindex - this is OK even if we don't move onto new */
  2892.     /* RFD because it's not being used.                                      */
  2893.     /*                                                                       */
  2894.     /* Then see if we can let the receiver run - if not, we'll have to stop  */
  2895.     /* it and switch DMA etc.                                                */
  2896.     /*                                                                       */
  2897.     /* If we let the receiver run, we must calculate exactly where the data  */
  2898.     /* for the next frame is going to go!                                    */
  2899.     /*                                                                       */
  2900.     /* Note that if we are receiving into a given buffer, we always have the */
  2901.     /* rest of that buffer to play with, because we only strt using a new    */
  2902.     /* buffer if all received frames that were in it have been got out.      */
  2903.     /*************************************************************************/
  2904.  
  2905.     pNewRFD->StartIndex = CAST(pRFD->StartIndex + RcvdLength, short);
  2906.  
  2907.     if (CAST(pNewRFD->StartIndex, int) +
  2908.           CAST(pDX->LinkMaxFrameSize, int) +
  2909.           2                             /* +2 for possible CRC dribble       */
  2910.         < RCVDATABUF_SIZE)              /* (and some more paranoia).         */
  2911.     {
  2912.       /***********************************************************************/
  2913.       /* next packet fits into this buffer - can let receiver run            */
  2914.       /***********************************************************************/
  2915.  
  2916.       pNewRFD->BufPtr    = pRFD->BufPtr;
  2917.       pNewRFD->StartAddr = &pNewRFD->BufPtr->Data[pNewRFD->StartIndex];
  2918.       MustStopReceiver   = FALSE;
  2919.     }
  2920.     else
  2921.     {
  2922.       /***********************************************************************/
  2923.       /* This buffer is hopeless, so how about the other one - have all it's */
  2924.       /* frams been pulled?  If so, we can use it                            */
  2925.       /***********************************************************************/
  2926.  
  2927.       if (RCVBUF_INUSE(pRFD->BufPtr->OtherBuffer))
  2928.       {
  2929.         CanMoveOn = FALSE;              /* cant use him either               */
  2930.       }
  2931.       else
  2932.       {
  2933.         /* use other buffer */
  2934.         pNewRFD->BufPtr    = pRFD->BufPtr->OtherBuffer;
  2935.         pNewRFD->StartIndex= 0;
  2936.         pNewRFD->StartAddr = &pNewRFD->BufPtr->Data[0];
  2937.       }
  2938.     }
  2939.   }
  2940.  
  2941.   /***************************************************************************/
  2942.   /* If necessary, stop the receiver                                         */
  2943.   /***************************************************************************/
  2944.  
  2945.   if (MustStopReceiver)
  2946.   {
  2947.     RxFSMActionStop (pDX);
  2948.   }
  2949.  
  2950.   /***************************************************************************/
  2951.   /* If we will be moving on, do it & increment the count of waiting frames. */
  2952.   /* Whatever happens, we must signal that RFD is empty via RcvdDataLength       */
  2953.   /***************************************************************************/
  2954.  
  2955.    if (CanMoveOn)
  2956.    {
  2957.      RFD_PUT(pDX);
  2958.  
  2959.      pDX->RcvInfo.RFDNowBeingPut = NewNBP;
  2960.      pRFD                        = pNewRFD;
  2961.      pDX->pIR->RxFrameCount++;          /* show Rx frame available           */
  2962.    }
  2963.    pRFD->RcvdDataLength = -1;           /* empty !                           */
  2964.  
  2965.   TRACE_OBJECT(Rp, (*pRFD));
  2966.   XTRACE_DWORD (pRFD);
  2967.   XTRACE_OBJECT(Rb, (*(pRFD->BufPtr)));
  2968.   XTRACE_ACTION(Rs, pRFD->StartIndex);
  2969.  
  2970.   /***************************************************************************/
  2971.   /* A frame is ready for the application (or the buffer is full and the     */
  2972.   /* application should do some receiving) - set the flag so that its        */
  2973.   /* semaphore will be cleared by the ISR when we return.                    */
  2974.   /***************************************************************************/
  2975.  
  2976.   pDX->DPCAction |= DPC_ACTION_PULSE;
  2977.  
  2978.   /***************************************************************************/
  2979.   /* Now call the action routine to restart the receiver.                    */
  2980.   /***************************************************************************/
  2981.  
  2982.   RxFSMActionStart (pDX);
  2983.  
  2984.   TRACE_EVENT (ROk;);
  2985. }
  2986.  
  2987. /*****************************************************************************/
  2988. /*                                                                           */
  2989. /* Name         RxFSMEvent                                                   */
  2990. /*                                                                           */
  2991. /* Purpose      Interprets inputs from the Request handlers and from the     */
  2992. /*              ISR and calls the relevant action routines.                  */
  2993. /*                                                                           */
  2994. /*              There are two fundamental states:                            */
  2995. /*                                                                           */
  2996. /*              - idle                                                       */
  2997. /*              - ready (i.e. receiver is active)                            */
  2998. /*                                                                           */
  2999. /*              Each of these states, however, can also exist in two states  */
  3000. /*              depending on the activity of the transmitter which has to    */
  3001. /*              restrain the receiver when it is using the DMA.  These sub-  */
  3002. /*              states are idle(held) and ready(held).                       */
  3003. /*                                                                           */
  3004. /* Purpose      Routes processing to the relevant action routines.  The FSM  */
  3005. /*              action must be synchronized.  The action routines are allowed*/
  3006. /*              to call back to the FSM.                                     */
  3007. /*                                                                           */
  3008. /* Params    IN pDX                                                          */
  3009. /*              FSMInput - the input value                                   */
  3010. /*              Implicit - pDX->RxResultBuffer result bytes pulled from      */
  3011. /*                              Rx status register on 8273                   */
  3012. /*                                                                           */
  3013. /*          OUT Action routine called and new state set.                     */
  3014. /*                                                                           */
  3015. /*****************************************************************************/
  3016.  
  3017. void RxFSMEvent (PDX pDX, int Input)
  3018. {
  3019.   RXFSMENTRY *e      = &RxFSM [Input] [pDX->RxFSMCurState];
  3020.  
  3021.   /***************************************************************************/
  3022.   /* The FSM consists of a 'state' which is actually the address of the      */
  3023.   /* current FSM 'column'.  The 'input' is an offset down the column at      */
  3024.   /* which is located an action routine address and a new state.             */
  3025.   /***************************************************************************/
  3026.  
  3027.   TRACE_EVENT (<RFE);
  3028.  
  3029.   ASSERT (pDX->RxFSMCurState < RXFSMSTATECOUNT);
  3030.   ASSERT (Input              < RXFSMINPUTCOUNT);
  3031.   TRACE_EVENTNAME(RxFSMStateNames[pDX->RxFSMCurState]);
  3032.   TRACE_EVENTNAME(RxFSMInputNames[Input]);
  3033.  
  3034.   /***************************************************************************/
  3035.   /* Reset the state to the new state specified in the FSM table             */
  3036.   /* (Important to do this before the actions because some of them then do   */
  3037.   /* recursive calls to FSMEvent                                             */
  3038.   /***************************************************************************/
  3039.  
  3040.   pDX->RxFSMCurState = e->NewState;
  3041.   ASSERT (e->NewState        <  RXFSMSTATECOUNT);
  3042.   TRACE_EVENTNAME(RxFSMStateNames[pDX->RxFSMCurState]);
  3043.  
  3044.   /***************************************************************************/
  3045.   /* Do the action specified by the FSM table entry                          */
  3046.   /***************************************************************************/
  3047.   (*(e->pRxActionRoutine)) (pDX);
  3048.  
  3049.   TRACE_EVENT (RFE>);
  3050. }
  3051.  
  3052. /*****************************************************************************/
  3053. /*                                                                           */
  3054. /* Name         FSMNullAction                                                */
  3055. /*                                                                           */
  3056. /* Purpose      Carries out a 'nul' action for both Tx and Rx FSM            */
  3057. /*                                                                           */
  3058. /*****************************************************************************/
  3059.  
  3060. void FSMNullAction (PDX pDX)
  3061. {
  3062.   UNREFERENCED_PARAMETER (pDX);
  3063.   return;
  3064. }
  3065.  
  3066. /**PROC+**********************************************************************/
  3067. /*                                                                           */
  3068. /* Name         SetLinkConfig (pDX)                                          */
  3069. /*                                                                           */
  3070. /* Purpose      Link Configuration Characteristics set-up.                   */
  3071. /*              Primes the 8273 and V24 interface in the manner required     */
  3072. /*              required by a particular set of link configuration options.  */
  3073. /*                                                                           */
  3074. /* Params    IN Link Options byte (pDX->LinkOptions) set up                  */
  3075. /*              Implicit input: the adapter has been reset and is ready to go*/
  3076. /*                                                                           */
  3077. /*          OUT Hardware is set up as indicated or carry set.                */
  3078. /*                                                                           */
  3079. /* Return Value BOOLean:    TRUE if options set up OK, otherwise FALSE       */
  3080. /*                                                                           */
  3081. /**PROC-**********************************************************************/
  3082.  
  3083. BOOLean SetLinkConfig (PDX pDX)
  3084. {
  3085.   UCHAR o;
  3086.   BOOLean rc;
  3087.  
  3088.   TRACE_EVENT (<SLC);
  3089.  
  3090.   ASSERT (pDX->HardwareError EQ FALSE);   /* Reset function should turn off  */
  3091.                                           /* hardware error flag             */
  3092.  
  3093.   /***************************************************************************/
  3094.   /* Check the configuration bits and use the data to set up the mode set    */
  3095.   /* and reset commands held on the LCB.  Then run through the whole batch   */
  3096.   /* in a tight loop at the end.                                             */
  3097.   /***************************************************************************/
  3098.  
  3099.   /***************************************************************************/
  3100.   /* Operating mode                                                          */
  3101.   /***************************************************************************/
  3102.   o = AP_OMBFR;                           /* assume default (buffered)       */
  3103.   if (pDX->LinkOptionsByte & LinkOption_HDLC)
  3104.   {
  3105.     o |= AP_OMX25;                        /* set HDLC Abort                  */
  3106.   }
  3107.  
  3108.   pDX->CmdStringSetOpMode[2]  = CAST(o, UCHAR);
  3109.   pDX->CmdStringResetOpMode[2]= CAST(o | APR_OM, UCHAR);
  3110.  
  3111.   /***************************************************************************/
  3112.   /* Serial IO Mode                                                          */
  3113.   /***************************************************************************/
  3114.   o = 0;                                /* assume SIO mode is NRZ */
  3115.   if (pDX->LinkOptionsByte & LinkOption_NRZI)           /* then check for NRZI selected */
  3116.   {
  3117.     o |= AP_IONZI;                      /* set NRZI bit in the mask */
  3118.   }
  3119.   pDX->CmdStringSetSerialIOMode[2]= CAST (o, UCHAR);
  3120.   pDX->CmdStringResetSerialIOMode[2]= CAST (o | APR_IO, UCHAR);
  3121.                                           /* set the unused bits for reset */
  3122.   /***************************************************************************/
  3123.   /* Sort out DMA.  Assume for now we will be able to use an architectural   */
  3124.   /* NT-defined way of avoiding conflicts on DMA channels,                   */
  3125.   /***************************************************************************/
  3126.  
  3127.   pDX->CmdStringDataTransferMode[0]= 0x97;/* assume Data Transfer is PIO */
  3128.   pDX->CmdStringDataTransferMode[2]= 1;
  3129.   pDX->GrabbedResources &= ~GRABBEDRESOURCE_GOTDMA; /*and clear DMA privelege*/
  3130.  
  3131.   if (pDX->LinkOptionsByte & LinkOption_DMA &&  /* DMA Requested ?           */
  3132.       pDX->ConfigData.DMAChannel NE 0)          /* and DMA possible for card */
  3133.   {
  3134.     /*************************************************************************/
  3135.     /* Read this link's configured DMA channel and check for non-0           */
  3136.     /*************************************************************************/
  3137.  
  3138. ///////////////////////////////////////////////////////////////////////////////
  3139. // guff to do with protecting ourselves from other guy using same DMA channel
  3140. // reinstate later if necessary
  3141. //
  3142. //      if <SI eq <offset SELCBL1>>
  3143. //
  3144. //         mov DI,offset SELCBL2
  3145. //
  3146. //      else
  3147. //
  3148. //         mov DI,offset SELCBL1
  3149. //
  3150. //      }
  3151. //
  3152. //     /**********************************************************************/
  3153. //     /* Check whether the links use the same DMA and grab it if not.       */
  3154. //     /* Otherwise look to see whether the other link does not currently    */
  3155. //     /* have DMA.                                                          */
  3156. //     /**********************************************************************/
  3157. //
  3158. //      if <AL ne pDX->DMAChan> OR
  3159. //      test pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA
  3160. //      if z
  3161. ///////////////////////////////////////////////////////////////////////////////
  3162.  
  3163.     pDX->GrabbedResources |= GRABBEDRESOURCE_GOTDMA; /*  register ownership! */
  3164.     pDX->DMAIsActive      =  FALSE;
  3165.     pDX->CmdStringDataTransferMode[0]= 0x57;     /*  and set DT mode to DMA  */
  3166.     pDX->CmdStringDataTransferMode[2]= 0xFE;     /* ..rather than interrupts */
  3167.  
  3168.     /*************************************************************************/
  3169.     /* If this is MCA Extended DMA then we have to set up an I/O transfer    */
  3170.     /* address.                                                              */
  3171.     /*************************************************************************/
  3172.  
  3173.     if (pDX->ConfigData.DMAChannel NE StandardDMAChannel)
  3174.     {
  3175. ///////////////////////////////////////////////////////////////////////////////
  3176. //?ML?
  3177. // from semdh.asm
  3178. //                  and AL,0fh                  ;clear top four bits
  3179. //                  out LDD_DMAEFR,AL           ;write out the fncn cmnd
  3180. //
  3181. //                  mov AX,LCB.LCBPrtBase
  3182. //                  add AX,LDD_73Data
  3183. //                  out LDD_DMAEFE,AL           ;write out the LOB
  3184. //                  SEPDHDLY            ;let it take effect
  3185. //                  mov AL,AH
  3186. //                  out LDD_DMAEFE,AL           ;write out the HOB
  3187. //////////////////////////////////////////////////////////////////////////////
  3188.  
  3189.       USHORT Addr = CAST(pDX->ADAPTERBASE+AR_8273D, USHORT);
  3190.  
  3191.       WR_N_DELAY (DMAExtdFnRegister, CAST(pDX->ConfigData.DMAChannel & 0x0F,  \
  3192.                                           UCHAR));
  3193.       WR_N_DELAY (DMAExtdFnRegister, LOBYTE(Addr));   /* write out the LOB   */
  3194.       WR_N_DELAY (DMAExtdFnRegister, HIBYTE(Addr));   /* and HOB             */
  3195.     }
  3196.   }
  3197.  
  3198.   /***************************************************************************/
  3199.   /* Now actually issue the mode setting commands to the 8273.               */
  3200.   /***************************************************************************/
  3201.  
  3202.   Write8273Cmd(pDX,pDX->CmdStringResetOpMode);
  3203.   Write8273Cmd(pDX,pDX->CmdStringResetSerialIOMode);
  3204.   Write8273Cmd(pDX,pDX->CmdStringSetOpMode);
  3205.   Write8273Cmd(pDX,pDX->CmdStringSetSerialIOMode);
  3206.   Write8273Cmd(pDX,pDX->CmdStringDataTransferMode);
  3207.   rc = !pDX->HardwareError;
  3208.  
  3209.   TRACE_RCFALSE(rc);
  3210.   TRACE_EVENT (SLC>);
  3211.   return (rc);
  3212. }
  3213.  
  3214. /**PROC+**********************************************************************/
  3215. /*                                                                           */
  3216. /* Name         SetV24Output (                                               */
  3217. /*                            PDX pDX                                        */
  3218. /*                           );                                              */
  3219. /*                                                                           */
  3220. /* Purpose      Primes the 8273 and V24 interfaces as requested in IR->V24Out*/
  3221. /*                                                                           */
  3222. /* Params   IN  pDX - the device extension                                   */
  3223. /*              Implicit input: V24Out byte in IR is what is to be pumped out*/
  3224. /*                                                                           */
  3225. /* Return Value BOOLean: TRUE if commands etc. correctly written             */
  3226. /*                                                                           */
  3227. /* Operation                                                                 */
  3228. /*                                                                           */
  3229. /**PROC-**********************************************************************/
  3230.  
  3231. BOOLean SetV24Output (PDX pDX)
  3232. {
  3233.   /**********************************************************************/
  3234.   /* Do the 8255 Port B settings first.  Note that their sense is      */
  3235.   /* logically inverted and 0 = ON.                                    */
  3236.   /*********************************************************************/
  3237.  
  3238.   UCHAR o;
  3239.   UCHAR V24Out = pDX->pIR->V24Out;
  3240.  
  3241.   o = 8;                                /* NOT reset modem status logic      */
  3242.   o |= (V24Out & IR_OV24DSRS)           /* user wants DSRS on?               */
  3243.        ? 0                              /* 0 in port B turns on DSRS         */
  3244.        : 1;
  3245.   o |= (V24Out & IR_OV24SlSt)           /* user wants Select Standby on?     */
  3246.        ? 0                              /* 0 in port B turns on Select Stndby*/
  3247.        : 2;
  3248.   o |= (V24Out & IR_OV24Test)           /* user wants Test on?               */
  3249.        ? 0                              /* 0 in port B turns on Test         */
  3250.        : 4;
  3251.  
  3252.   WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, o);
  3253.  
  3254.   /*********************************************************************/
  3255.   /* Now do the 8273 Port B settings.                                  */
  3256.   /*********************************************************************/
  3257.  
  3258.   o = 0;
  3259.   o |= (V24Out & IR_OV24RTS)            /* user wants RTS up?                */
  3260.        ? 1
  3261.        : 0;
  3262.   o |= (V24Out & IR_OV24DTR)            /* user wants DTR up?                */
  3263.        ? 4
  3264.        : 0;
  3265.  
  3266.   pDX->CmdStringSetPortB[2]= o;               /* save value in 'set' cmd     */
  3267.   pDX->CmdStringResetPortB[2]= CAST(0xC0 | o, UCHAR);
  3268.                                               /* and also in 'reset' cmd     */
  3269.  
  3270.   Write8273Cmd (pDX,pDX->CmdStringSetPortB);    /* turn on what should be on */
  3271.   Write8273Cmd (pDX,pDX->CmdStringResetPortB); /*and turn off what shouldn't*/
  3272.  
  3273.   return(!pDX->HardwareError);
  3274. }
  3275.  
  3276. /*****************************************************************************/
  3277. /*                                                                           */
  3278. /* Name         StartDMA (                                                   */
  3279. /*                        PDX              pDX                               */
  3280. /*                        PHYSICAL_ADDRESS PhysicalAddress                   */
  3281. /*                        USHORT           BufferLength                      */
  3282. /*                        UCHAR            OpCode                            */
  3283. /*                       );                                                  */
  3284. /*                                                                           */
  3285. /* Purpose      Issues a Receive/Transmit command to the DMA.  The address   */
  3286. /*              and length information are all in registers, other than the  */
  3287. /*              segment physical base address which is in global data.       */
  3288. /*                                                                           */
  3289. /* Params    IN PhysicalAddress (not System VAS address!)                    */
  3290. /*              BufferLength is maximum data length                          */
  3291. /*              (although the 8273 controls exactly how many transfers are   */
  3292. /*              pulled).  So this count really acts as a stopper and should  */
  3293. /*              (due to stupid design of 8273) be one less than overflow val */
  3294. /*              OpCode is DMACmdRead/Write                                   */
  3295. /*                                                                           */
  3296. /*          OUT Command issued to DMA.                                       */
  3297. /*                                                                           */
  3298. /* Modified:    31/03/88 Initial coding                                      */
  3299. /*                                                                           */
  3300. /*****************************************************************************/
  3301.  
  3302. void StartDMA(PDX              pDX,
  3303.               PHYSICAL_ADDRESS PhysicalAddress,
  3304.               USHORT           BufferLength,
  3305.               UCHAR            OpCode)
  3306. {
  3307.   PHYSICAL_ADDRESS a;
  3308.   USHORT           b;
  3309.  
  3310.   TRACE_EVENT (<SDM);
  3311.  
  3312.   ASSERT (!DMACrosses64K(PhysicalAddress.LowPart, BufferLength));
  3313.  
  3314.   /***************************************************************************/
  3315.   /* First, test whether the channel number is set to 1.  If not, then this  */
  3316.   /* is an MCA machine using a non-standard channel, so dothe MCA version of */
  3317.   /* this routine                                                            */
  3318.   /***************************************************************************/
  3319.  
  3320.   if (pDX->ConfigData.DMAChannel EQ StandardDMAChannel)/* good ole channel one       */
  3321.   {
  3322.     /*************************************************************************/
  3323.     /* Mask off the channel we're about to play with.                        */
  3324.     /*************************************************************************/
  3325.  
  3326.     IO_OUT (DMAMaskRegister, DMAMaskChannel1);
  3327.  
  3328.     /*************************************************************************/
  3329.     /* The hard part is generating an address to give the DMA chip.  We      */
  3330.     /* already know, because initialisation ensures it, that the buffer will */
  3331.     /* not span a 64k boundary, but we have to generate the full physical    */
  3332.     /* address from the offset supplied in DI and the physical address of    */
  3333.     /* DGROUP read in during initialisation.                                 */
  3334.     /*************************************************************************/
  3335.  
  3336.     IO_OUT (DMAFirstByteFlipFlop,0);    /* data ignored, OUT resets FF       */
  3337.  
  3338.     a = PhysicalAddress;
  3339.  
  3340.     WR_N_DELAY (DMAPhysAddress, a.LowPart & 0xFF);  /* first, set physaddr low byte  */
  3341.     a.LowPart = a.LowPart >> 8;
  3342.     WR_N_DELAY (DMAPhysAddress, a.LowPart  & 0xFF);  /* next, set physaddr high byte  */
  3343.     a.LowPart = a.LowPart >> 8;
  3344.     WR_N_DELAY (DMAPageRegister,a.LowPart  & 0xFF)   /* finally 64k page register value*/
  3345.  
  3346.     /*************************************************************************/
  3347.     /* Next give the chip the maximum size count passed in BufferLength.     */
  3348.     /*************************************************************************/
  3349.  
  3350.     WR_N_DELAY (DMAFirstByteFlipFlop,0);    /* ML did this so I will too ?   */
  3351.  
  3352.     b = BufferLength;
  3353.     WR_N_DELAY (DMACountRegister, a.LowPart & 0xFF);
  3354.     b = b >> 8;
  3355.     WR_N_DELAY (DMACountRegister, a.LowPart & 0xFF);
  3356.  
  3357.     /*************************************************************************/
  3358.     /* Set up the mode value as passed in.                                   */
  3359.     /*************************************************************************/
  3360.  
  3361.     WR_N_DELAY (DMAModeRegister, OpCode);
  3362.  
  3363.     /*************************************************************************/
  3364.     /* Finally kick the chip off by clearing the channel mask bit.           */
  3365.     /*************************************************************************/
  3366.  
  3367.     IO_OUT (DMAMaskRegister, DMAClearChannel1);
  3368.  
  3369.   }
  3370.   else
  3371.   {
  3372.     /*************************************************************************/
  3373.     /* This must be an MCA machine with programmable DMA channels.  The only */
  3374.     /* actual option at present is '7' for the second MPA/A.                 */
  3375.     /*************************************************************************/
  3376.  
  3377.     ASSERT (pDX->ConfigData.DMAChannel EQ 7);
  3378.  
  3379.     /*************************************************************************/
  3380.     /* Set the mask for this channel.                                        */
  3381.     /*************************************************************************/
  3382.  
  3383.     IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMASetMask);
  3384.  
  3385.     /*************************************************************************/
  3386.     /* Give the DMA registers the data xfer start address.                   */
  3387.     /*************************************************************************/
  3388.  
  3389.     IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMAAddress);
  3390.  
  3391.     a = PhysicalAddress;
  3392.  
  3393.     WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF);      /* and then set address bits 0-7 */
  3394.     a.LowPart = a.LowPart >> 8;
  3395.     WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF);      /* set address bits 8 - 15       */
  3396.     a.LowPart = a.LowPart >> 8;
  3397.     WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF);      /* set address bits 16 - 23      */
  3398.  
  3399.     /*************************************************************************/
  3400.     /* Now set up the maximum xfer count.                                    */
  3401.     /*************************************************************************/
  3402.  
  3403.     IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMACount);
  3404.  
  3405.     a.LowPart = BufferLength;
  3406.     WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF);      /* length low byte               */
  3407.     a.LowPart = a.LowPart >> 8;
  3408.     WR_N_DELAY (DMAExtdFnRegister, a.LowPart & 0xFF);      /* length high byte              */
  3409.  
  3410.     /*************************************************************************/
  3411.     /* Now set the mode register for the channel (read/write).  This is done */
  3412.     /* on the basis of the original old-style mode being for read or for     */
  3413.     /* write.                                                                */
  3414.     /*************************************************************************/
  3415.  
  3416.     IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMAMode);
  3417.  
  3418.     WR_N_DELAY (DMAExtdFnRegister, (OpCode EQ DMACmdWrite) ? 0x0D : 0x05);
  3419.  
  3420.     /*************************************************************************/
  3421.     /* Last job is to reset the mask register for the channel.               */
  3422.     /*************************************************************************/
  3423.  
  3424.      IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMAClearMask);
  3425.   }
  3426.   pDX->DMAIsActive = TRUE;
  3427.   TRACE_EVENT (SDM>);
  3428. }
  3429.  
  3430. /*****************************************************************************/
  3431. /*                                                                           */
  3432. /* Name         StopDMA                                                      */
  3433. /*                                                                           */
  3434. /* Purpose      Link Device Driver Stop DMA Routine.                         */
  3435. /*                                                                           */
  3436. /*              Kills the DMA by masking the appropriate channel.            */
  3437. /*                                                                           */
  3438. /* Params    IN pDX                                                          */
  3439. /*              Implicit: DMA channel allocated                              */
  3440. /*                                                                           */
  3441. /*          OUT Command issued to DMA.                                       */
  3442. /*                                                                           */
  3443. /*****************************************************************************/
  3444.  
  3445. void StopDMA (PDX pDX)
  3446. {
  3447.   TRACE_EVENT (<ZDM);
  3448.  
  3449.   ASSERT (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA);
  3450.  
  3451.   if (pDX->ConfigData.DMAChannel EQ StandardDMAChannel)
  3452.   {
  3453.     /*************************************************************************/
  3454.     /* Channel #1 - set the mask directly.                                   */
  3455.     /*************************************************************************/
  3456.  
  3457.     IO_OUT (DMAMaskRegister, DMAMaskChannel1);
  3458.   }
  3459.   else
  3460.   {
  3461.     /*************************************************************************/
  3462.     /* Not channel 1 - set the mask using the Extended function addressing   */
  3463.     /* register.                                                             */
  3464.     /*************************************************************************/
  3465.  
  3466.     IO_OUT (DMAExtdFnRegister, pDX->ConfigData.DMAChannel | MCADMASetMask);
  3467.   }
  3468.   pDX->DMAIsActive = FALSE;
  3469.   TRACE_EVENT (ZDM>);
  3470. }
  3471.  
  3472. /**PROC+**********************************************************************/
  3473. /*                                                                           */
  3474. /* Name:        SynchReset8273 (                                             */
  3475. /*                          PDEVICE_OBJECT pDeviceObject                     */
  3476. /*                         )                                                 */
  3477. /*                                                                           */
  3478. /* Purpose:     Reset the 8273 and set the 'Closing' flag so that following  */
  3479. /*              interrupts are ignored (until we disable)                    */
  3480. /*              with interrupt processing                                    */
  3481. /*                                                                           */
  3482. /* Params:   IN Context         is really pDX                                */
  3483. /*                                                                           */
  3484. /* Return Value:None                                                         */
  3485. /*                                                                           */
  3486. /* Operation:                                                                */
  3487. /*                                                                           */
  3488. /*                                                                           */
  3489. /**PROC-**********************************************************************/
  3490.  
  3491. BOOLEAN SynchReset8273 (PVOID Context)
  3492. {
  3493.   PDX pDX = (PDX) Context;
  3494.   TRACE_EVENT (<XR8);
  3495.  
  3496.   pDX->AdapterIsClosing = TRUE;
  3497.   AdapterReset (pDX);
  3498.  
  3499.   TRACE_EVENT(XR8>);
  3500.  
  3501.   return (FALSE);
  3502. }
  3503.  
  3504. /**PROC+**********************************************************************/
  3505. /*                                                                           */
  3506. /* Name:        SynchTerminateAdapter(                                       */
  3507. /*                          PDEVICE_OBJECT pDeviceObject                     */
  3508. /*                         )                                                 */
  3509. /*                                                                           */
  3510. /* Purpose:     Close a particular device - stuff that needs to be interlockd*/
  3511. /*              with interrupt processing                                    */
  3512. /*                                                                           */
  3513. /* Params:   IN Context         is really pDX                                */
  3514. /*                                                                           */
  3515. /* Return Value:None                                                         */
  3516. /*                                                                           */
  3517. /* Operation:                                                                */
  3518. /*                                                                           */
  3519. /*                                                                           */
  3520. /**PROC-**********************************************************************/
  3521.  
  3522. BOOLEAN SynchTerminateAdapter (PVOID Context)
  3523. {
  3524.   PDX pDX = (PDX) Context;
  3525.   TRACE_EVENT (<XTA);
  3526.  
  3527.   TerminateAdapter (pDX);
  3528.  
  3529.   TRACE_EVENT(XTA>);
  3530.  
  3531.   return (FALSE);
  3532. }
  3533.  
  3534. /**PROC+**********************************************************************/
  3535. /*                                                                           */
  3536. /* Name:        SynchEntryPointOpen (                                        */
  3537. /*                          PDEVICE_OBJECT pDeviceObject                     */
  3538. /*                         )                                                 */
  3539. /*                                                                           */
  3540. /* Purpose:     Initialise the next device (from GetDriverSpec)              */
  3541. /*                                                                           */
  3542. /* Params:   IN Context         is really pDX                                */
  3543. /*                                                                           */
  3544. /* Return Value:BOOLEAN:        True if object opened OK                     */
  3545. /*                                                                           */
  3546. /* Operation:                                                                */
  3547. /*              1. Copy over pre-initialised data sequences                  */
  3548. /*                                                                           */
  3549. /*                                                                           */
  3550. /**PROC-**********************************************************************/
  3551.  
  3552. BOOLEAN SynchEntryPointOpen (PVOID Context)
  3553. {
  3554.   PDX pDX = (PDX) Context;
  3555.   BOOLEAN rc;
  3556.   TRACE_EVENT (<XEO);
  3557.  
  3558.   rc = CAST (InitialiseAdapter (pDX), BOOLEAN);
  3559.                                         /* if OK, InitAdapter returns TRUE   */
  3560.   TRACE_EVENT(XEO>);
  3561.   return (rc);
  3562. }
  3563.  
  3564. /*****************************************************************************/
  3565. /*                                                                           */
  3566. /* Name         TerminateAdapter                                             */
  3567. /*                                                                           */
  3568. /* Purpose      Link Device Driver Hardware Termination.                     */
  3569. /*                                                                           */
  3570. /*              Does the physical termination, but leaves assigned resurces  */
  3571. /*              still assigned                                               */
  3572. /*                                                                           */
  3573. /* Params    IN pDX                                                          */
  3574. /*                                                                           */
  3575. /*          OUT Hardware is cleared down.                                    */
  3576. /*                                                                           */
  3577. /*****************************************************************************/
  3578.  
  3579. void TerminateAdapter (PDX pDX)
  3580. {
  3581.   /***************************************************************************/
  3582.   /* Reset the 8255 and 8273.                                                */
  3583.   /***************************************************************************/
  3584.  
  3585.   IO_OUT (pDX->ADAPTERBASE + AR_8255B, A55_Reset8273On);
  3586.  
  3587.   /***************************************************************************/
  3588.   /* Documentation says use a long delay while resetting!                    */
  3589.   /* (but I'm blowed if I can find where it says it.  Try 10 microsecs.)     */
  3590.   /***************************************************************************/
  3591.  
  3592.   KeStallExecutionProcessor (10L);
  3593.  
  3594.   WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, A55_Reset8273Off);
  3595.   WR_N_DELAY (pDX->ADAPTERBASE + AR_8255B, A55_Reset8273Off);
  3596.  
  3597.   IO_OUT (pDX->ADAPTERBASE + AR_8255C, A55_ResetPortC);
  3598.  
  3599.   /***************************************************************************/
  3600.   /* Ensure that an MPCA is completely 'turned off'.                         */
  3601.   /***************************************************************************/
  3602.  
  3603.   if (pDX->ConfigData.MPCAModePort NE 0)
  3604.   {
  3605.     IO_OUT (pDX->ConfigData.MPCAModePort, AC_MPCAD); /* MPCAD = disable       */
  3606.     TRACE_DATABYTE (Mpc, AC_MPCAD);
  3607.   }
  3608.  
  3609.   /***************************************************************************/
  3610.   /* Check whether this channel was using the DMA and clear it down.         */
  3611.   /***************************************************************************/
  3612.  
  3613.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  3614.   {
  3615.     StopDMA(pDX);                        /* stop the channel doing anything */
  3616.     pDX->GrabbedResources &= ~GRABBEDRESOURCE_GOTDMA;
  3617.   }
  3618. }
  3619.  
  3620. /****************************************************************************/
  3621. /*                                                                          */
  3622. /* Name         TxFSMActionAbort                                                    */
  3623. /*                                                                          */
  3624. /* Purpose      Aborts the current transmission.                            */
  3625. /*                                                                          */
  3626. /* Params    IN pDX.  Transmitter going presumably.                         */
  3627. /*                                                                          */
  3628. /*          OUT Receiver started                                            */
  3629. /*                                                                          */
  3630. /****************************************************************************/
  3631.  
  3632. void TxFSMActionAbort (PDX pDX)
  3633. {
  3634.   TRACE_EVENT (TAb:);
  3635.  
  3636.   Write8273Cmd (pDX, pDX->CmdStringAbortTransmit);
  3637.  
  3638.   TRACE_EVENT (TAb;);
  3639. }
  3640.  
  3641. /****************************************************************************/
  3642. /*                                                                          */
  3643. /* Name         TxFSMActionEndError                                                    */
  3644. /*                                                                          */
  3645. /* Purpose      Handles Tx error conditions by recording and retrying       */
  3646. /*                                                                          */
  3647. /*              Updates statistics,                                         */
  3648. /*              Restarts the transmitter.                                   */
  3649. /*                                                                          */
  3650. /* Params    IN pDX, 8273 result code in TxResult                           */
  3651. /*                                                                          */
  3652. /*          OUT Tx Stats updated, transmitter restarted                     */
  3653. /*                                                                          */
  3654. /****************************************************************************/
  3655.  
  3656. void TxFSMActionEndError (PDX pDX)
  3657. {
  3658.   TRACE_EVENT (TEr:);
  3659.  
  3660.   /*********************************************************************/
  3661.   /* Check whether DMA is supported and kill the DMA Channel if so.    */
  3662.   /*********************************************************************/
  3663.  
  3664.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  3665.   {
  3666.     StopDMA (pDX);
  3667.     XASSERT (!pDX->DMAIsActive);
  3668.   }
  3669.  
  3670.   /***************************************************************************/
  3671.   /* Increment the stats count and set the flag to pulse the event           */
  3672.   /***************************************************************************/
  3673.  
  3674.   pDX->pIR->StatusCount++;
  3675.   pDX->DPCAction |= DPC_ACTION_PULSE;
  3676.  
  3677.   /***************************************************************************/
  3678.   /* Basically we translate the error to an index into the stats array held  */
  3679.   /* in the interface record and increment it.                               */
  3680.   /***************************************************************************/
  3681.  
  3682.   TRACE_DATABYTE (TEb, pDX->TxResult);
  3683.  
  3684.   if (pDX->TxResult EQ ATxR_ErrTxUnderrun)
  3685.   {
  3686.     /*************************************************************************/
  3687.     /* Check how many times we have tried to resend this frame.  If this was */
  3688.     /* the third attempt then give up, otherwise try again.                  */
  3689.     /*************************************************************************/
  3690.  
  3691.     pDX->TxConsecutiveUnderrunCount++;      /* increment count of underruns  */
  3692.     if (pDX->TxConsecutiveUnderrunCount > 2)
  3693.     {
  3694.       TxFSMActionEndOK(pDX);                /* forget this frame - pretend OK*/
  3695.     }
  3696.     else
  3697.     {
  3698.        TxFSMEvent (pDX, TxFSMInputStart);   /* tell FSM to send again        */
  3699.     }
  3700.  
  3701.     pDX->pIR->StatusArray[SA_TxUnderrun]++; /* transmitter underrun          */
  3702.   }
  3703.   else if (pDX->TxResult EQ ATxR_ErrTxCTSDrop)
  3704.   {
  3705.     TxFSMActionEndOK (pDX);                 /* forget this frame - pretend OK*/
  3706.     pDX->pIR->StatusArray[SA_CTSDrop]++;    /* clear to send dropped         */
  3707.   }
  3708.   else
  3709.   {
  3710.     TxFSMActionEndOK (pDX);                 /* forget this frame - pretend OK*/
  3711.     pDX->pIR->StatusArray[SA_HardwareError]++;
  3712.                                             /* unknown result byte!          */
  3713.   }
  3714.  
  3715.   TRACE_EVENT (TEr;);
  3716. }
  3717.  
  3718. /****************************************************************************/
  3719. /*                                                                          */
  3720. /* Name         TxFSMActionEndOK                                                    */
  3721. /*                                                                          */
  3722. /* Purpose      Frame transmission complete.                                */
  3723. /*                                                                          */
  3724. /*              Handles the frame transmission completion actions.          */
  3725. /*              Updates the Tx buffer data.                                 */
  3726. /*              Starts the next transmission if data is available.          */
  3727. /*                                                                          */
  3728. /* Params    IN pDX                                                         */
  3729. /*                                                                          */
  3730. /*          OUT Tx Data Buffer updated                                      */
  3731. /*                                                                          */
  3732. /****************************************************************************/
  3733.  
  3734. void TxFSMActionEndOK (PDX pDX)
  3735. {
  3736.   USHORT FreedLength;                   /* how many bytes freed up from bufr */
  3737.  
  3738.   TRACE_EVENT (TOk:);
  3739.  
  3740.   /*********************************************************************/
  3741.   /* Check whether DMA is supported and kill the DMA Channel if so.    */
  3742.   /*********************************************************************/
  3743.  
  3744.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  3745.   {
  3746.     StopDMA (pDX);
  3747.     XASSERT (!pDX->DMAIsActive);
  3748.   }
  3749.  
  3750.   /*********************************************************************/
  3751.   /* Clear the count of consecutive transmitter underruns.             */
  3752.   /*********************************************************************/
  3753.  
  3754.   pDX->TxConsecutiveUnderrunCount = 0;
  3755.  
  3756.   /***************************************************************************/
  3757.   /* Read the 'tail' and work out the length of the area freed up by the     */
  3758.   /* completion of this transmission.  Divide that by two and add it to the  */
  3759.   /* 'maximum' Tx frame size on the interface.  The 'max' is in fact half    */
  3760.   /* the total size of the transmit buffer (with some allowance for length   */
  3761.   /* words and rounding up) because the free area within the buffer can be   */
  3762.   /* broken into at most two non-contiguous sections.                        */
  3763.   /***************************************************************************/
  3764.  
  3765.   FreedLength = CAST(MAKEUSHORT (pDX->pSendBuf[pDX->TxNextToTransmit  ],  \
  3766.                                  pDX->pSendBuf[pDX->TxNextToTransmit+1])
  3767.                            + 2,         /* +2 : freeing up length as well    */
  3768.                      USHORT);
  3769.  
  3770.   pDX->pIR->TxMaxFrSizeNow += (FreedLength + 1) / 2;
  3771.                                         /* making sure we round UP!          */
  3772.   XTRACE_ACTION (Tz, pDX->pIR->TxMaxFrSizeNow);
  3773.  
  3774.   /***************************************************************************/
  3775.   /* Calculate the new next-to-transmit point, wrapping if necessary         */
  3776.   /***************************************************************************/
  3777.  
  3778.   pDX->TxNextToTransmit += FreedLength;
  3779.   if (pDX->TxNextToTransmit >= pDX->TxStartUnusedArea)
  3780.   {
  3781.     /*************************************************************************/
  3782.     /* The last buffer we sent was the right-most in the buffer - so we must */
  3783.     /* reset the unused area and NextToTranmsit                              */
  3784.     /*************************************************************************/
  3785.  
  3786.     pDX->TxStartUnusedArea = SENDBUF_SIZE;
  3787.     pDX->TxNextToTransmit  = 0;
  3788.     XTRACE_ACTION (Tu, pDX->TxStartUnusedArea);
  3789.    }
  3790.    XTRACE_ACTION (Tt, pDX->TxNextToTransmit);
  3791.  
  3792.  
  3793.   /***************************************************************************/
  3794.   /* Now check whether there is more data in the buffer and send it.  If     */
  3795.   /* there are no more frames, check whether the application has finished    */
  3796.   /* the current transmission and stop the transmitter if so.                */
  3797.   /***************************************************************************/
  3798.  
  3799.   if (pDX->TxNextToTransmit NE pDX->TxNextToBuffer)
  3800.   {
  3801.     TxFSMEvent (pDX, TxFSMInputStart);
  3802.   }
  3803.   else
  3804.   {
  3805.     /*************************************************************************/
  3806.     /* The buffer is empty so we need to stop the transmitter if we are half */
  3807.     /* duplex and we have indeed sent the poll/final bit (as defined in the  */
  3808.     /* 'C' byte of the last transmit command (ooh, it's so tricky).          */
  3809.     /*************************************************************************/
  3810.  
  3811.     if (BITSOFF(pDX->LinkOptionsByte, LinkOption_FullDuplex) &&
  3812.         pDX->CmdStringTransmit[5] & POLLFINL
  3813.        )
  3814.     {
  3815.       TxFSMEvent (pDX, TxFSMInputStop);
  3816.     }
  3817.  
  3818.     /*************************************************************************/
  3819.     /* We have to tell the DLC software when the buffer goes empty.          */
  3820.     /*************************************************************************/
  3821.  
  3822.     pDX->DPCAction |= DPC_ACTION_PULSE; /* do a PULSE-EVENT from the DPC     */
  3823.   }
  3824.   TRACE_EVENT (TOk;);
  3825. }
  3826.  
  3827. /*****************************************************************************/
  3828. /*                                                                           */
  3829. /* Name         TxFSMActionInvalid                                                     */
  3830. /*                                                                           */
  3831. /* Purpose      Error input to FSM                                           */
  3832. /*                                                                           */
  3833. /*              This routine should never be called as it implies an         */
  3834. /*              'impossible state/input combination.  This is taken to mean  */
  3835. /*              that adapter status has been incorrectly reported and is     */
  3836. /*              treated as a hardware error.                                 */
  3837. /*                                                                           */
  3838. /* Params    IN pDX                                                          */
  3839. /*                                                                           */
  3840. /*          OUT Error processing started by RQ FSM input                     */
  3841. /*                                                                           */
  3842. /*****************************************************************************/
  3843.  
  3844. void TxFSMActionInvalid (PDX pDX)
  3845. {
  3846.   TRACE_EVENT(T!!!);
  3847.   pDX->pIR->StatusArray[SA_HardwareError]++;
  3848.   pDX->pIR->StatusCount++;
  3849.   pDX->DPCAction |= DPC_ACTION_PULSE;
  3850. }
  3851.  
  3852. /****************************************************************************/
  3853. /*                                                                          */
  3854. /* Name         TxFSMActionStart                                            */
  3855. /*                                                                          */
  3856. /* Purpose      Activates the Transmitter.                                  */
  3857. /*                                                                          */
  3858. /*              Raise RTS (if not raised already).                          */
  3859. /*              Start flag streaming.                                       */
  3860. /*              Stop the receiver (if not full duplex).                     */
  3861. /*              Initiate the first transmission.                            */
  3862. /*                                                                          */
  3863. /* Params    IN Data held in Device Object                                  */
  3864. /*                                                                          */
  3865. /*          OUT Transmitter Active and Transmit command issued.             */
  3866. /*                                                                          */
  3867. /****************************************************************************/
  3868.  
  3869. void TxFSMActionStart (PDX pDX)
  3870. {
  3871.   TRACE_EVENT (TSt:);
  3872.   /***************************************************************************/
  3873.   /* Put the transmitter into Flag Stream mode while it is active.           */
  3874.   /***************************************************************************/
  3875.  
  3876.   pDX->CmdStringSetOpMode[2] |= 1;      /* turn on flag stream mode          */
  3877.   Write8273Cmd (pDX, pDX->CmdStringSetOpMode);
  3878.  
  3879.   /***************************************************************************/
  3880.   /* Ensure that RTS is up.                                                  */
  3881.   /***************************************************************************/
  3882.  
  3883.   pDX->CmdStringSetPortB[2] |= 1;       /* 1 = RTS line - turn it up         */
  3884.   Write8273Cmd (pDX, pDX->CmdStringSetPortB);
  3885.   pDX->pIR->V24Out |= IR_OV24RTS;       /* record fact that RTS is on!       */
  3886.  
  3887.   /***************************************************************************/
  3888.   /* We are just starting the transmitter up.  If the link is not full       */
  3889.   /* duplex then stop the receiver while we are transmitting.                */
  3890.   /***************************************************************************/
  3891.  
  3892.   if (BITSOFF(pDX->LinkOptionsByte, LinkOption_FullDuplex))
  3893.   {
  3894.     RxFSMEvent (pDX, RxFSMInputHold);
  3895.   }
  3896.  
  3897.   /***************************************************************************/
  3898.   /* Lastly, start the first transmission.                                   */
  3899.   /***************************************************************************/
  3900.  
  3901.   TxFSMActionXmitNext (pDX);
  3902.   TRACE_EVENT (TSt;);
  3903.  
  3904. }
  3905.  
  3906. /*****************************************************************************/
  3907. /*                                                                           */
  3908. /* Name         TxFSMActionStop                                              */
  3909. /*                                                                           */
  3910. /* Purpose      Closes down the transmitter                                  */
  3911. /*                                                                           */
  3912. /*              Drops RTS (if 2-wire)                                        */
  3913. /*              Stops flag stream and (if not HDLC)                          */
  3914. /*              Re-enables the receiver (if half duplex)                     */
  3915. /*                                                                           */
  3916. /* Params    IN pDX                                                          */
  3917. /*                                                                           */
  3918. /*          OUT Receiver started if HDX                                      */
  3919. /*                                                                           */
  3920. /*****************************************************************************/
  3921.  
  3922. void TxFSMActionStop (PDX pDX)
  3923. {
  3924.   TRACE_EVENT (TZap);
  3925.   /*********************************************************************/
  3926.   /* Check whether DMA is supported and kill the DMA Channel if so.    */
  3927.   /*********************************************************************/
  3928.  
  3929.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  3930.   {
  3931.     StopDMA (pDX);
  3932.     XASSERT (!pDX->DMAIsActive);
  3933.   }
  3934.  
  3935.   if (BITSOFF(pDX->LinkOptionsByte, LinkOption_4Wire))
  3936.   {
  3937.     /*************************************************************************/
  3938.     /* Modem 2-wire : Turn off RTS and drop it in the interface flags.       */
  3939.     /*************************************************************************/
  3940.  
  3941.      pDX->CmdStringSetPortB[2]   &= ~1;
  3942.      pDX->CmdStringResetPortB[2] &= ~1;
  3943.      Write8273Cmd (pDX, pDX->CmdStringResetPortB);
  3944.      pDX->pIR->V24Out &= ~IR_OV24RTS;   /* tell appl that RTS is off!        */
  3945.   }
  3946.  
  3947.   /*********************************************************************/
  3948.   /* Turn off Flag Stream Mode.                                        */
  3949.   /*********************************************************************/
  3950.  
  3951.   pDX->CmdStringSetOpMode[2]  &= ~1;
  3952.   pDX->CmdStringResetOpMode[2]&= ~1;
  3953.   Write8273Cmd (pDX, pDX->CmdStringResetOpMode);
  3954.  
  3955.   pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
  3956.  
  3957.   /*********************************************************************/
  3958.   /* Release the receiver if this is a half duplex link.               */
  3959.   /*********************************************************************/
  3960.  
  3961.   if (BITSOFF(pDX->LinkOptionsByte, LinkOption_FullDuplex))
  3962.   {
  3963.     RxFSMEvent (pDX, RxFSMInputRelease);
  3964.   }
  3965. }
  3966.  
  3967. /*****************************************************************************/
  3968. /*                                                                           */
  3969. /* Name         TxFSMActionXmitNext                                          */
  3970. /*                                                                           */
  3971. /* Purpose      Transmits the Next Frame in the Buffer                       */
  3972. /*                                                                           */
  3973. /*              Set up the transmit command                                  */
  3974. /*              Set up the DMA (if used)                                     */
  3975. /*              Issue the transmit command.                                  */
  3976. /*                                                                           */
  3977. /* Params    IN pDX, plus xmitter already active                             */
  3978. /*                                                                           */
  3979. /*              NextToTransmit: +0) length of buffered frame (A+C+data)      */
  3980. /*                              +1)                                          */
  3981. /*                              +2  A(ddress)                                */
  3982. /*                              +3  C(ontrol)                                */
  3983. /*                                                                           */
  3984. /*              Total buffer taken up is Length + 2.                         */
  3985. /*                                                                           */
  3986. /*          OUT Transmission under way.                                      */
  3987. /*                                                                           */
  3988. /*****************************************************************************/
  3989.  
  3990. void TxFSMActionXmitNext (PDX pDX)
  3991. {
  3992.   USHORT LengthFor8273;
  3993.   UCHAR *p;
  3994.   UCHAR  TempLo;
  3995.   UCHAR  TempHi;
  3996.  
  3997.   TRACE_EVENT (TSn:);
  3998.  
  3999.   /***************************************************************************/
  4000.   /* Before issuing the transmit command, read in the current Port A value   */
  4001.   /* as we won't be able to if both the transmitter and receiver become      */
  4002.   /* active concurrently.                                                    */
  4003.   /***************************************************************************/
  4004.  
  4005.   pDX->LastPortA = Write8273Cmd (pDX, pDX->CmdStringReadPortA);
  4006.  
  4007.   /***************************************************************************/
  4008.   /* Read the current tail position and check for a buffer wrap (tail =      */
  4009.   /* current length of buffer).                                              */
  4010.   /***************************************************************************/
  4011.  
  4012.   if (pDX->TxNextToTransmit >= pDX->TxStartUnusedArea)
  4013.   {
  4014.     /*************************************************************************/
  4015.     /* The last buffer we sent was the right-most in the buffer - so we must */
  4016.     /* reset the unused area and NextToTranmsit                              */
  4017.     /*************************************************************************/
  4018.  
  4019.     pDX->TxStartUnusedArea = SENDBUF_SIZE;
  4020.     pDX->TxNextToTransmit  = 0;
  4021.     XTRACE_ACTION (Tu, pDX->TxStartUnusedArea);
  4022.     XTRACE_ACTION (Tt, pDX->TxNextToTransmit);
  4023.   }
  4024.  
  4025.   /***************************************************************************/
  4026.   /* Found the next frame - read its length and set up Tx Command.           */
  4027.   /***************************************************************************/
  4028.  
  4029.   p = &pDX->pSendBuf[pDX->TxNextToTransmit];
  4030.   TempLo = *(p++);                              /* first two bytes are length*/
  4031.   TempHi = *(p++);
  4032.   LengthFor8273 = CAST (TempLo + (TempHi <<8)-2,/* allow for the buffered A+C*/
  4033.                         USHORT);
  4034.  
  4035.   ASSERT (CAST(LengthFor8273, int  ) < pDX->LinkMaxFrameSize);
  4036.   ASSERT (CAST(LengthFor8273, short) >= 0);
  4037.  
  4038.   pDX->CmdStringTransmit[2] = LOBYTE(LengthFor8273);
  4039.                                         /* and put it into the cmd           */
  4040.   pDX->CmdStringTransmit[3] = HIBYTE(LengthFor8273);
  4041.  
  4042.   /***************************************************************************/
  4043.   /* and set up the (buffered) A & C in the command                          */
  4044.   /***************************************************************************/
  4045.  
  4046.   TRC_IN_DW (*p);
  4047.   pDX->CmdStringTransmit[4] = *(p++);           /* next two bytes are A&C    */
  4048.   pDX->CmdStringTransmit[5] = *(p++);
  4049.  
  4050.   pDX->pTxPIOData = p;                          /* next is PIO data start pos*/
  4051.   TRACE_EVENT (TPIO);
  4052.   TRACE_DWORD (pDX->pTxPIOData);
  4053.  
  4054.   /***************************************************************************/
  4055.   /* Now prime the DMA if necessary                                          */
  4056.   /***************************************************************************/
  4057.  
  4058.   if (pDX->GrabbedResources & GRABBEDRESOURCE_GOTDMA)
  4059.   {
  4060.     PHYSICAL_ADDRESS L;
  4061.     if (pDX->DMAIsActive)
  4062.     {
  4063.       StopDMA (pDX);
  4064.       XASSERT (!pDX->DMAIsActive);
  4065.     }
  4066.  
  4067.  
  4068.     L = pDX->SendBufPhysAddr;
  4069.     L.LowPart += pDX->TxNextToTransmit + 4;
  4070.  
  4071.     StartDMA(pDX,
  4072.              L,
  4073.              LengthFor8273,              /* but 8273 will control how many snt*/
  4074.              DMACmdRead                  /* set the mode */
  4075.             );
  4076.     XASSERT (pDX->DMAIsActive);
  4077.   }
  4078.  
  4079.   /******************************************************************/
  4080.   /* Lastly, issue the transmit command to the 8273.                */
  4081.   /******************************************************************/
  4082.  
  4083.   Write8273Cmd (pDX, pDX->CmdStringTransmit);
  4084.  
  4085.   TRACE_EVENT (TSn;);
  4086. }
  4087.  
  4088. /****************************************************************************/
  4089. /*                                                                          */
  4090. /* Name         TxFSMEvent                                                  */
  4091. /*                                                                          */
  4092. /* Purpose      Interprets inputs from the Request handlers and from the    */
  4093. /*              ISR and calls the relevant action routines.                 */
  4094. /*                                                                          */
  4095. /* Params    IN pDX, and FSM input                                          */
  4096. /*                                                                          */
  4097. /*          OUT Action routine called and new state set.                    */
  4098. /*                                                                          */
  4099. /****************************************************************************/
  4100.  
  4101. void TxFSMEvent (PDX pDX, int Input)
  4102. {
  4103.   TXFSMENTRY *e      = &TxFSM [Input] [pDX->TxFSMCurState];
  4104.  
  4105.   /***************************************************************************/
  4106.   /* The FSM consists of a 'state' which is actually the address of the      */
  4107.   /* current FSM 'column'.  The 'input' is an offset down the column at      */
  4108.   /* which is located an action routine address and a new state.             */
  4109.   /***************************************************************************/
  4110.  
  4111.   TRACE_EVENT (<TFE);
  4112.  
  4113.   ASSERT (pDX->TxFSMCurState < TXFSMSTATECOUNT);
  4114.   ASSERT (Input              < TXFSMINPUTCOUNT);
  4115.   TRACE_EVENTNAME(TxFSMStateNames[pDX->TxFSMCurState]);
  4116.   TRACE_EVENTNAME(TxFSMInputNames[Input]);
  4117.  
  4118.   /***************************************************************************/
  4119.   /* Reset the state to the new state specified in the FSM table             */
  4120.   /* (Important to do this before the actions because some of them then do   */
  4121.   /* recursive calls to FSMEvent                                             */
  4122.   /***************************************************************************/
  4123.  
  4124.   pDX->TxFSMCurState = e->NewState;
  4125.   ASSERT (e->NewState        <  TXFSMSTATECOUNT);
  4126.   TRACE_EVENTNAME(TxFSMStateNames[pDX->TxFSMCurState]);
  4127.  
  4128.   (*(e->pTxActionRoutine)) (pDX);
  4129.  
  4130.   TRACE_EVENT (TFE>);
  4131.  
  4132. }
  4133.  
  4134. /**PROC+**********************************************************************/
  4135. /*                                                                           */
  4136. /* Name         Write8273Cmd (                                               */
  4137. /*                            PDX    pDX                                     */
  4138. /*                            UCHAR *Cmd;                                    */
  4139. /*                           );                                              */
  4140. /*                                                                           */
  4141. /* Purpose      Send out a command array (in <cmd>, <length>, <params> format*/
  4142. /*                                                                           */
  4143. /* Params   IN  pDX - the device extension                                   */
  4144. /*          IN  Cmd - ptr to first char of command                           */
  4145. /*                                                                           */
  4146. /* Return Value If command is READ 8273 PORT A/B return value read, otherwise*/
  4147. /*              return value is meaningless.                                 */
  4148. /*                                                                           */
  4149. /* Operation    None                                                         */
  4150. /*                                                                           */
  4151. /* Notes        1. <length> may be 0                                         */
  4152. /*              2. Write8273Cmd (OS/2 DD precursor of this routine used to   */
  4153. /*                 return carry on error.  We don't bother as this was only  */
  4154. /*                 check in one place.                                       */
  4155. /*                                                                           */
  4156. /**PROC-**********************************************************************/
  4157.  
  4158. UCHAR Write8273Cmd (PDX pDX, UCHAR *Cmd)
  4159. {
  4160.   int   ParameterCount;
  4161.   UCHAR Result = 0;
  4162.  
  4163.   TRACE_EVENT (<Cmd);
  4164.   TRACE_CHAR (*Cmd);                    /* trace command and first 3 params  */
  4165.   TRACE_CHAR (*(Cmd+2));
  4166.   TRACE_CHAR (*(Cmd+3));
  4167.   TRACE_CHAR (*(Cmd+4));
  4168.  
  4169.   WAITUNTIL(pDX,AS_CMBSY|AS_CMBFF,EQ,0);/* wait for busy and full to go off  */
  4170.   if (pDX->HardwareError)               /* stop if previous error or error   */
  4171.     return(0);                          /* this time                         */
  4172.  
  4173.   IO_OUT (pDX->ADAPTERBASE+AR_8273S,    /* status reg also command register  */
  4174.           *Cmd++);                      /* command is first byte             */
  4175.  
  4176.   if (*(Cmd-1) EQ 0x22 || *(Cmd-1) EQ 0x23)
  4177.   {                                     /* what we sent out was Read Port A/B*/
  4178.     WAITUNTIL(pDX,AS_CRBFF,EQ,AS_CRBFF);/* wait for result buff full to go on*/
  4179.     Result = IO_IN (pDX->ADAPTERBASE+AR_8273P);
  4180.   }
  4181.   ParameterCount = *(Cmd++);            /* parameter count is next           */
  4182.   while (ParameterCount--)
  4183.   {
  4184.     WAITUNTIL (pDX,                     /* wait for busy to go on, but       */
  4185.           (AS_CMBSY|AS_CMBFF|AS_CPBFF), /* command and param buffs are clear */
  4186.                EQ, AS_CMBSY);
  4187.  
  4188.     IO_OUT (pDX->ADAPTERBASE+AR_8273P, /* write params to parameter port     */
  4189.             (UCHAR)*(Cmd++));
  4190.   }
  4191.  
  4192.   TRACE_EVENT (Cmd>);
  4193.   return(Result);
  4194. }
  4195.  
  4196. /*****************************************************************************/
  4197. /*                                                                           */
  4198. /* Name         LogDriverError                                               */
  4199. /*                                                                           */
  4200. /* Purpose      Allocates an error log entry, copies over the given info     */
  4201. /*              and writes it to the error log file.                         */
  4202. /*                                                                           */
  4203. /* Params    IN pDeviceObject                                                */
  4204. /*           IN FinalStatus       : NT Status returned to calling service    */
  4205. /*           IN UniqueErrorValue  : bottom word is the resource message id   */
  4206. /*           IN MajorFunctionCode : for the current Irp                      */
  4207. /*           IN IoControlCode     : Ioctl code                               */
  4208. /*                                                                           */
  4209. /*****************************************************************************/
  4210.  
  4211. VOID LogDriverError (
  4212.                      PDEVICE_OBJECT pDeviceObject,
  4213.                      NTSTATUS       FinalStatus,
  4214.                      ULONG          UniqueErrorValue,
  4215.                      UCHAR          MajorFunctionCode,
  4216.                      ULONG          IoControlCode
  4217.                     )
  4218. {
  4219.   PIO_ERROR_LOG_PACKET ErrorLogEntry;
  4220.  
  4221.   TRACE_EVENT (<LDE);
  4222.  
  4223.   ErrorLogEntry = IoAllocateErrorLogEntry(
  4224.                       pDeviceObject,
  4225.                       (UCHAR)sizeof(IO_ERROR_LOG_PACKET)
  4226.                       );
  4227.  
  4228.   if (ErrorLogEntry NE NULL)
  4229.   {
  4230.     ErrorLogEntry->ErrorCode         = UniqueErrorValue;
  4231.  
  4232.     ErrorLogEntry->FinalStatus       = FinalStatus;
  4233.     ErrorLogEntry->UniqueErrorValue  = UniqueErrorValue;
  4234.     ErrorLogEntry->MajorFunctionCode = MajorFunctionCode;
  4235.     ErrorLogEntry->IoControlCode     = IoControlCode;
  4236.  
  4237.     ErrorLogEntry->SequenceNumber = pDeviceObject->ReferenceCount;
  4238.  
  4239.     IoWriteErrorLogEntry(ErrorLogEntry);
  4240.   }
  4241.  
  4242.   TRACE_EVENT (LDE>);
  4243. }
  4244.  
  4245.  
  4246. /*****************************************************************************/
  4247. /* Notes.                                                                    */
  4248. /*                                                                           */
  4249. /* 1. The OS/2 device driver registers the MPA interrupt 3 as exclusive but  */
  4250. /* then shares it internally.  We can't do this unfortunately on NT because  */
  4251. /* IoConnectInterrupt requires the device object as a parameter.  We will    */
  4252. /* therefore have to register MPAA interrupts as shared.  The problem with   */
  4253. /* the shared interrupts on OS/2 was that phantom interrupts could be        */
  4254. /* generated (and, because we didn't have to service any cards, the          */
  4255. /* interrupt request stayed asserted).  As NT is well-designed and tested,   */
  4256. /* this won't occur so we can use shared interrupts.                         */
  4257. /*                                                                           */
  4258. /* 2. Should we action receive results immediately?  As background, we do    */
  4259. /* action all events immediately except for Transmitter results which are    */
  4260. /* passed to the DPC routine.  NT religious dogma says we should not action  */
  4261. /* the rx result immediately either, but pass them to the DPC routine.  The  */
  4262. /* danger in doing this is that we will miss the start of the next frame.    */
  4263. /* This isn't a problem in DMA, because we're just letting it rip.  But in   */
  4264. /* PIO mode, we can be some while getting to restart the receiver if we drop */
  4265. /* down to DPC level.  So... action al rx interrupts immediately.            */
  4266. /*                                                                           */
  4267. /*                                                                           */
  4268. /*****************************************************************************/
  4269.  
  4270.  
  4271. //on termination, unlock any locked memory and free the MDLs (e.g.
  4272. //InterfaceRecordMdl)
  4273. //
  4274. //need to initialise InterfaceRecordMdl = NULL
  4275.